Upload source code aplikasi KopiKaoCare

This commit is contained in:
DeaBaasithian 2026-08-03 11:34:15 +07:00
commit a99d618102
108 changed files with 5260 additions and 0 deletions

15
.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties

3
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

1
.idea/.name Normal file
View File

@ -0,0 +1 @@
Projek TA

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AndroidProjectSystem">
<option name="providerId" value="com.android.tools.idea.GradleProjectSystem" />
</component>
</project>

6
.idea/compiler.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="21" />
</component>
</project>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetSelector">
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
</selectionStates>
</component>
</project>

17
.idea/deviceManager.xml Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DeviceTable">
<option name="columnSorters">
<list>
<ColumnSorterState>
<option name="column" value="Name" />
<option name="order" value="ASCENDING" />
</ColumnSorterState>
<ColumnSorterState>
<option name="column" value="Type" />
<option name="order" value="ASCENDING" />
</ColumnSorterState>
</list>
</option>
</component>
</project>

18
.idea/gradle.xml Normal file
View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="CHOOSE_PER_TEST" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

16
.idea/misc.xml Normal file
View File

@ -0,0 +1,16 @@
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
<component name="VisualizationToolProject">
<option name="state">
<ProjectState>
<option name="scale" value="0.19237365722656252" />
</ProjectState>
</option>
</component>
</project>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
<option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
<option value="com.intellij.execution.junit.PatternConfigurationProducer" />
<option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
<option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
<option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
</set>
</option>
</component>
</project>

1
app/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

112
app/build.gradle.kts Normal file
View File

@ -0,0 +1,112 @@
plugins {
alias(libs.plugins.android.application)
}
android {
namespace = "com.example.projekta"
compileSdk = 36
defaultConfig {
applicationId = "com.example.projekta"
minSdk = 24
targetSdk = 33
versionCode = 1
versionName = "1.0"
testInstrumentationRunner =
"androidx.test.runner.AndroidJUnitRunner"
}
packaging {
resources {
excludes += setOf(
"META-INF/INDEX.LIST",
"META-INF/DEPENDENCIES",
"META-INF/io.netty.versions.properties",
"META-INF/LICENSE*",
"META-INF/NOTICE*"
)
}
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile(
"proguard-android-optimize.txt"
),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility =
JavaVersion.VERSION_11
targetCompatibility =
JavaVersion.VERSION_11
}
buildFeatures {
viewBinding = true
}
}
dependencies {
// ANDROID
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
implementation(libs.androidx.activity)
implementation(libs.androidx.constraintlayout)
// RECYCLERVIEW
implementation(
"androidx.recyclerview:recyclerview:1.3.2"
)
// CIRCLE IMAGE
implementation(
"de.hdodenhof:circleimageview:3.1.0"
)
// IMAGE LOADER
implementation(
"io.coil-kt:coil:2.6.0"
)
// VOLLEY
implementation(
"com.android.volley:volley:1.2.1"
)
// SPLASH SCREEN
implementation(
"androidx.core:core-splashscreen:1.0.1"
)
// MQTT
implementation("com.hivemq:hivemq-mqtt-client:1.3.3")
// TEST
testImplementation(libs.junit)
androidTestImplementation(
libs.androidx.junit
)
androidTestImplementation(
libs.androidx.espresso.core
)
}

21
app/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -0,0 +1,24 @@
package com.example.projekta
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.example.projekta", appContext.packageName)
}
}

View File

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- INTERNET -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!-- CAMERA -->
<uses-permission android:name="android.permission.CAMERA" />
<!-- STORAGE Android 13+ -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<!-- STORAGE Android 12 ke bawah -->
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<!-- CAMERA OPTIONAL -->
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.ProjekTA"
android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/network_security_config"
>
<!-- SPLASH -->
<activity
android:name=".SplashActivity"
android:exported="true"
android:theme="@style/Theme.ProjekTA.Splash">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- LOGIN -->
<activity android:name=".SignInActivity" android:exported="false" />
<activity android:name=".LoginActivity" android:exported="false" />
<activity android:name=".RegisterActivity" android:exported="false" />
<!-- MENU -->
<activity android:name=".MenuActivity" android:exported="false" />
<!-- PROFILE -->
<activity android:name=".ProfileActivity" android:exported="false" />
<!-- MENU DETAIL -->
<activity android:name=".PemupukanActivity" android:exported="false" />
<activity android:name=".MetodePemupukanActivity" android:exported="false" />
<activity android:name=".PanelSuryaActivity" android:exported="false" />
<activity android:name=".PanduanActivity" android:exported="false" />
<activity android:name=".TentangActivity" android:exported="false" />
<!-- HISTORI -->
<activity android:name=".HistoriActivity" android:exported="false" />
<!-- MAIN -->
<activity android:name=".MainActivity" android:exported="false" />
</application>
</manifest>

View File

@ -0,0 +1,120 @@
package com.example.projekta
import android.os.Bundle
import android.widget.ImageView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.volley.Request
import com.android.volley.toolbox.JsonArrayRequest
import com.android.volley.toolbox.Volley
import org.json.JSONObject
class HistoriActivity : AppCompatActivity() {
private lateinit var recyclerHistori: RecyclerView
private lateinit var historiList:
ArrayList<HistoriModel>
private lateinit var historiAdapter:
HistoriAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_histori)
// ================= BACK =================
val btnBack =
findViewById<ImageView>(R.id.btnBack)
btnBack.setOnClickListener {
finish()
}
// ================= RECYCLERVIEW =================
recyclerHistori =
findViewById(R.id.recyclerHistori)
recyclerHistori.layoutManager =
LinearLayoutManager(this)
historiList = ArrayList()
historiAdapter =
HistoriAdapter(
this,
historiList
)
recyclerHistori.adapter =
historiAdapter
// ================= LOAD HISTORI =================
loadHistori()
}
private fun loadHistori() {
val url =
"http://192.168.43.191/projekta/get_histori.php"
val request = JsonArrayRequest(
Request.Method.GET,
url,
null,
{ response ->
historiList.clear()
for (i in 0 until response.length()) {
val data: JSONObject =
response.getJSONObject(i)
val histori = HistoriModel(
createdAt =
data.getString("created_at"),
jamPemupukan =
data.getString("jam_pemupukan"),
mode =
data.getString("mode"),
durasiPompa =
data.getString("durasi_pompa"),
intervalHari =
data.getString("interval_hari"),
statusTanah =
data.getString("status_tanah")
)
historiList.add(histori)
}
historiAdapter.notifyDataSetChanged()
},
{
Toast.makeText(
this,
"Gagal mengambil histori",
Toast.LENGTH_SHORT
).show()
}
)
Volley.newRequestQueue(this)
.add(request)
}
}

View File

@ -0,0 +1,95 @@
package com.example.projekta
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.cardview.widget.CardView
import androidx.recyclerview.widget.RecyclerView
class HistoriAdapter(
private val context: Context,
private val historiList: ArrayList<HistoriModel>
) : RecyclerView.Adapter<HistoriAdapter.ViewHolder>() {
class ViewHolder(itemView: View)
: RecyclerView.ViewHolder(itemView) {
val tvTanggal: TextView =
itemView.findViewById(R.id.tvTanggal)
val tvJam: TextView =
itemView.findViewById(R.id.tvJam)
val tvMode: TextView =
itemView.findViewById(R.id.tvMode)
val tvDurasi: TextView =
itemView.findViewById(R.id.tvDurasi)
val tvInterval: TextView =
itemView.findViewById(R.id.tvInterval)
val tvStatusTanah: TextView =
itemView.findViewById(R.id.tvStatusTanah)
val cardHistori: CardView =
itemView.findViewById(R.id.cardHistori)
}
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): ViewHolder {
val view = LayoutInflater.from(context)
.inflate(
R.layout.item_histori,
parent,
false
)
return ViewHolder(view)
}
override fun onBindViewHolder(
holder: ViewHolder,
position: Int
) {
val histori =
historiList[position]
// TANGGAL
holder.tvTanggal.text =
histori.createdAt
// JAM
holder.tvJam.text =
histori.jamPemupukan
// MODE
holder.tvMode.text =
"• Mode: ${histori.mode}"
// DURASI
holder.tvDurasi.text =
"• Durasi: ${histori.durasiPompa}"
// INTERVAL
holder.tvInterval.text =
"• Interval: ${histori.intervalHari}"
// STATUS TANAH
holder.tvStatusTanah.text =
"🔥 Status Tanah: ${histori.statusTanah}"
}
override fun getItemCount(): Int {
return historiList.size
}
}

View File

@ -0,0 +1,17 @@
package com.example.projekta
data class HistoriModel(
val createdAt: String = "",
val jamPemupukan: String = "",
val mode: String = "",
val durasiPompa: String = "",
val intervalHari: String = "",
val statusTanah: String = ""
)

View File

@ -0,0 +1,216 @@
package com.example.projekta
import android.content.Intent
import android.os.Bundle
import android.text.InputType
import android.util.Patterns
import android.view.MotionEvent
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.android.volley.Request
import com.android.volley.toolbox.StringRequest
import com.android.volley.toolbox.Volley
import com.example.projekta.databinding.ActivityLoginBinding
import org.json.JSONObject
class LoginActivity : AppCompatActivity() {
private lateinit var binding: ActivityLoginBinding
private var isPasswordVisible = false
private val url = "http://192.168.43.191/projekta/login.php"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityLoginBinding.inflate(layoutInflater)
setContentView(binding.root)
// =========================
// CEK SESSION LOGIN
// =========================
val sharedPref = getSharedPreferences("LOGIN", MODE_PRIVATE)
if (sharedPref.getBoolean("isLogin", false)) {
startActivity(Intent(this, MenuActivity::class.java))
finish()
}
binding.btnBack.setOnClickListener {
finish()
}
setupPasswordToggle()
binding.btnLogin.setOnClickListener {
val email = binding.etEmail.text.toString().trim()
val password = binding.etPassword.text.toString()
// VALIDASI EMAIL
if (email.isEmpty() || !Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
binding.etEmail.error = "Email tidak valid"
return@setOnClickListener
}
// VALIDASI PASSWORD
if (password.length < 6) {
binding.etPassword.error = "Password minimal 6 karakter"
return@setOnClickListener
}
loginUser(email, password)
}
binding.txtRegister.setOnClickListener {
startActivity(Intent(this, RegisterActivity::class.java))
}
}
// =========================
// LOGIN USER
// =========================
private fun loginUser(email: String, password: String) {
val request = object : StringRequest(
Request.Method.POST,
url,
{ response ->
try {
val json = JSONObject(response)
if (json.getString("status") == "success") {
val idUser = json.getString("id")
val nama = json.getString("nama")
val emailUser = json.getString("email")
// SIMPAN SESSION LOGIN
val sharedPref = getSharedPreferences("LOGIN", MODE_PRIVATE)
sharedPref.edit()
.putBoolean("isLogin", true)
.putString("id_user", idUser)
.putString("nama", nama)
.putString("email", emailUser)
.apply()
Toast.makeText(
this,
"Login berhasil",
Toast.LENGTH_SHORT
).show()
startActivity(Intent(this, MenuActivity::class.java))
finish()
} else {
Toast.makeText(
this,
"Email / Password salah",
Toast.LENGTH_SHORT
).show()
}
} catch (e: Exception) {
Toast.makeText(
this,
"Response server tidak valid",
Toast.LENGTH_LONG
).show()
e.printStackTrace()
}
},
{
Toast.makeText(
this,
"Gagal koneksi server",
Toast.LENGTH_LONG
).show()
}
) {
override fun getParams(): MutableMap<String, String> {
val params = HashMap<String, String>()
params["email"] = email
params["password"] = password
return params
}
}
Volley.newRequestQueue(this).add(request)
}
// =========================
// PASSWORD TOGGLE
// =========================
private fun setupPasswordToggle() {
binding.etPassword.setOnTouchListener { _, event ->
val drawableEnd = 2
if (event.action == MotionEvent.ACTION_UP) {
val drawable = binding.etPassword.compoundDrawables[drawableEnd]
if (drawable != null &&
event.rawX >= (binding.etPassword.right - drawable.bounds.width())
) {
isPasswordVisible = !isPasswordVisible
if (isPasswordVisible) {
binding.etPassword.inputType =
InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
binding.etPassword.setCompoundDrawablesWithIntrinsicBounds(
R.drawable.ic_lock,
0,
R.drawable.ic_eye_off,
0
)
} else {
binding.etPassword.inputType =
InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
binding.etPassword.setCompoundDrawablesWithIntrinsicBounds(
R.drawable.ic_lock,
0,
R.drawable.ic_eye,
0
)
}
binding.etPassword.setSelection(binding.etPassword.text.length)
return@setOnTouchListener true
}
}
false
}
}
}

View File

@ -0,0 +1,22 @@
package com.example.projekta
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.example.projekta.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// tes klik layar
binding.root.setOnClickListener {
println("App jalan 🔥")
}
}
}

View File

@ -0,0 +1,136 @@
package com.example.projekta
import android.content.Context
import android.content.Intent
import android.graphics.BitmapFactory
import android.os.Bundle
import android.util.Base64
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.GravityCompat
import com.example.projekta.databinding.ActivityMenuBinding
class MenuActivity : AppCompatActivity() {
private lateinit var binding: ActivityMenuBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMenuBinding.inflate(layoutInflater)
setContentView(binding.root)
loadUserSidebar()
// Buka Drawer
binding.btnMenu.setOnClickListener {
binding.drawerLayout.openDrawer(GravityCompat.START)
}
// Menu Profile
binding.menuProfile.setOnClickListener {
startActivity(Intent(this, ProfileActivity::class.java))
binding.drawerLayout.closeDrawer(GravityCompat.START)
}
// Menu Logout
binding.menuLogout.setOnClickListener {
getSharedPreferences("LOGIN", MODE_PRIVATE).edit().clear().apply()
getSharedPreferences("USER_DATA", MODE_PRIVATE).edit().clear().apply()
val intent = Intent(this, LoginActivity::class.java)
intent.flags =
Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(intent)
finish()
}
// Menu Pemupukan
binding.menuPemupukan.setOnClickListener {
startActivity(Intent(this, PemupukanActivity::class.java))
}
// Menu Panel Surya
binding.menuPanelSurya.setOnClickListener {
startActivity(Intent(this, PanelSuryaActivity::class.java))
}
// Menu Panduan
binding.menuPanduan.setOnClickListener {
startActivity(Intent(this, PanduanActivity::class.java))
}
// Menu Tentang
binding.menuTentang.setOnClickListener {
startActivity(Intent(this, TentangActivity::class.java))
}
// Menu Histori
binding.menuHistori.setOnClickListener {
startActivity(Intent(this, HistoriActivity::class.java))
}
// Tombol Back
onBackPressedDispatcher.addCallback(
this,
object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (binding.drawerLayout.isDrawerOpen(GravityCompat.START)) {
binding.drawerLayout.closeDrawer(GravityCompat.START)
} else {
finishAffinity()
}
}
}
)
}
// Refresh data sidebar setiap Activity kembali dibuka
override fun onResume() {
super.onResume()
loadUserSidebar()
}
// Memuat nama dan foto profil pada sidebar
private fun loadUserSidebar() {
val sharedPref = getSharedPreferences("USER_DATA", Context.MODE_PRIVATE)
val nama = sharedPref.getString("nama", "Nama Pengguna")
val foto = sharedPref.getString("foto", "")
binding.txtSidebarName.text = nama
if (!foto.isNullOrEmpty()) {
try {
val cleanBase64 = foto
.replace("\n", "")
.replace("\r", "")
.replace(" ", "")
val imageBytes = Base64.decode(cleanBase64, Base64.DEFAULT)
val bitmap = BitmapFactory.decodeByteArray(
imageBytes,
0,
imageBytes.size
)
binding.imgSidebarProfile.setImageBitmap(bitmap)
} catch (e: Exception) {
binding.imgSidebarProfile.setImageResource(R.drawable.profileman)
}
} else {
binding.imgSidebarProfile.setImageResource(R.drawable.profileman)
}
}
}

View File

@ -0,0 +1,389 @@
package com.example.projekta
import android.app.TimePickerDialog
import android.graphics.Color
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.cardview.widget.CardView
import com.android.volley.Request
import com.android.volley.toolbox.JsonObjectRequest
import com.android.volley.toolbox.StringRequest
import com.android.volley.toolbox.Volley
import java.util.Calendar
import java.util.Locale
class MetodePemupukanActivity : AppCompatActivity() {
private lateinit var btnBack: ImageView
private lateinit var cardAuto: CardView
private lateinit var cardManual: CardView
private lateinit var etInterval: EditText
private lateinit var etDurasi: EditText
private lateinit var tvJam: TextView
private lateinit var btnPilihJam: Button
private lateinit var btnSimpan: Button
private lateinit var btnPompaManual: Button
private lateinit var tvStatusManual: TextView
private var mode = "otomatis"
private var isPompaOn = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_metode_pemupukan)
initView()
setupListener()
loadPengaturan()
}
private fun initView() {
btnBack = findViewById(R.id.btnBack)
cardAuto = findViewById(R.id.cardAuto)
cardManual = findViewById(R.id.cardManual)
etInterval = findViewById(R.id.etInterval)
etDurasi = findViewById(R.id.etDurasi)
tvJam = findViewById(R.id.tvJam)
btnPilihJam = findViewById(R.id.btnPilihJam)
btnSimpan = findViewById(R.id.btnSimpan)
btnPompaManual = findViewById(R.id.btnPompaManual)
tvStatusManual = findViewById(R.id.tvStatusManual)
}
private fun setupListener() {
btnBack.setOnClickListener {
finish()
}
cardAuto.setOnClickListener {
setModeOtomatis()
}
cardManual.setOnClickListener {
setModeManual()
}
btnPilihJam.setOnClickListener {
val calendar = Calendar.getInstance()
TimePickerDialog(
this,
{ _, hour, minute ->
tvJam.text = String.format(
Locale.getDefault(),
"%02d:%02d:00",
hour,
minute
)
},
calendar.get(Calendar.HOUR_OF_DAY),
calendar.get(Calendar.MINUTE),
true
).show()
}
btnPompaManual.setOnClickListener {
togglePompaManual()
}
btnSimpan.setOnClickListener {
simpanPengaturan()
}
}
private fun setModeOtomatis() {
mode = "otomatis"
etInterval.isEnabled = true
etDurasi.isEnabled = true
btnPilihJam.isEnabled = true
cardAuto.cardElevation = 12f
cardManual.cardElevation = 4f
}
private fun setModeManual() {
mode = "manual"
etInterval.isEnabled = false
etDurasi.isEnabled = false
btnPilihJam.isEnabled = false
cardAuto.cardElevation = 4f
cardManual.cardElevation = 12f
}
private fun togglePompaManual() {
if (mode != "manual") {
Toast.makeText(
this,
"Pilih MODE MANUAL terlebih dahulu",
Toast.LENGTH_SHORT
).show()
return
}
isPompaOn = !isPompaOn
if (isPompaOn) {
tvStatusManual.text = "STATUS: ON"
tvStatusManual.setTextColor(
Color.parseColor("#2E7D32")
)
btnPompaManual.text = "MATIKAN POMPA"
btnPompaManual.setBackgroundColor(
Color.parseColor("#D32F2F")
)
simpanHistori("manual", "ON")
} else {
tvStatusManual.text = "STATUS: OFF"
tvStatusManual.setTextColor(
Color.parseColor("#D32F2F")
)
btnPompaManual.text = "NYALAKAN POMPA"
btnPompaManual.setBackgroundColor(
Color.parseColor("#2E7D32")
)
simpanHistori("manual", "OFF")
}
}
private fun simpanPengaturan() {
if (mode == "otomatis") {
if (etInterval.text.toString().trim().isEmpty()) {
etInterval.error = "Isi interval hari"
return
}
if (etDurasi.text.toString().trim().isEmpty()) {
etDurasi.error = "Isi durasi detik"
return
}
}
val url =
"http://192.168.43.191/projekta/save_pengaturan.php"
val request = object : StringRequest(
Method.POST,
url,
{ response ->
Toast.makeText(
this,
response,
Toast.LENGTH_SHORT
).show()
},
{
Toast.makeText(
this,
"Gagal koneksi server",
Toast.LENGTH_SHORT
).show()
}
) {
override fun getParams(): MutableMap<String, String> {
val params = HashMap<String, String>()
params["mode"] = mode
if (mode == "otomatis") {
params["interval_hari"] =
etInterval.text.toString().trim()
params["durasi"] =
etDurasi.text.toString().trim()
params["jam"] =
tvJam.text.toString()
} else {
params["status_manual"] =
if (isPompaOn) "ON" else "OFF"
}
return params
}
}
Volley.newRequestQueue(this)
.add(request)
}
private fun simpanHistori(
modePemupukan: String,
statusPompa: String
) {
val url =
"http://192.168.43.191/projekta/insert_histori.php"
val request = object : StringRequest(
Request.Method.POST,
url,
{},
{}
) {
override fun getParams(): MutableMap<String, String> {
val params = HashMap<String, String>()
params["mode"] = modePemupukan
params["status"] = statusPompa
return params
}
}
Volley.newRequestQueue(this)
.add(request)
}
private fun loadPengaturan() {
val url =
"http://192.168.43.191/projekta/get_pengaturan.php"
val request = JsonObjectRequest(
Request.Method.GET,
url,
null,
{ response ->
try {
if (response.getBoolean("success")) {
mode =
response.getString("mode")
val interval =
response.getInt("interval_hari")
val durasi =
response.getInt("durasi")
val jam =
response.getString("jam")
val statusManual =
response.getString("status_manual")
tvJam.text = jam
etInterval.setText(
interval.toString()
)
etDurasi.setText(
durasi.toString()
)
if (mode == "manual") {
setModeManual()
if (statusManual == "ON") {
isPompaOn = true
tvStatusManual.text =
"STATUS: ON"
tvStatusManual.setTextColor(
Color.parseColor("#2E7D32")
)
btnPompaManual.text =
"MATIKAN POMPA"
btnPompaManual.setBackgroundColor(
Color.parseColor("#D32F2F")
)
} else {
isPompaOn = false
tvStatusManual.text =
"STATUS: OFF"
tvStatusManual.setTextColor(
Color.parseColor("#D32F2F")
)
btnPompaManual.text =
"NYALAKAN POMPA"
btnPompaManual.setBackgroundColor(
Color.parseColor("#2E7D32")
)
}
} else {
setModeOtomatis()
}
}
} catch (e: Exception) {
setModeOtomatis()
}
},
{
setModeOtomatis()
}
)
Volley.newRequestQueue(this)
.add(request)
}
}

View File

@ -0,0 +1,18 @@
package com.example.projekta
import android.os.Bundle
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
class PanduanActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_panduan)
val btnBack = findViewById<ImageView>(R.id.btnBack)
btnBack.setOnClickListener {
finish()
}
}
}

View File

@ -0,0 +1,145 @@
package com.example.projekta
import android.os.Bundle
import android.widget.Button
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.android.volley.Request
import com.android.volley.toolbox.JsonObjectRequest
import com.android.volley.toolbox.Volley
class PanelSuryaActivity : AppCompatActivity() {
private lateinit var tvStatusPanel: TextView
private lateinit var tvDaya: TextView
private lateinit var tvStatusDaya: TextView
private lateinit var tvSumberEnergi: TextView
private lateinit var tvStatusSistem: TextView
private lateinit var tvStatusPompa: TextView
private lateinit var tvUpdate: TextView
private lateinit var progressDaya: ProgressBar
private lateinit var btnRefresh: Button
private val url =
"http://192.168.43.191/projekta/get_panel_surya.php"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_panel_surya)
findViewById<ImageView>(R.id.btnBack).setOnClickListener {
finish()
}
tvStatusPanel = findViewById(R.id.tvStatusPanel)
tvDaya = findViewById(R.id.tvDaya)
tvStatusDaya = findViewById(R.id.tvStatusDaya)
tvSumberEnergi = findViewById(R.id.tvSumberEnergi)
tvStatusSistem = findViewById(R.id.tvStatusSistem)
tvStatusPompa = findViewById(R.id.tvStatusPompa)
tvUpdate = findViewById(R.id.tvUpdate)
progressDaya = findViewById(R.id.progressDaya)
btnRefresh = findViewById(R.id.btnRefresh)
ambilDataPanelSurya()
btnRefresh.setOnClickListener {
ambilDataPanelSurya()
}
}
private fun ambilDataPanelSurya() {
val request = JsonObjectRequest(
Request.Method.GET,
url,
null,
{ response ->
val statusPanel =
response.optString("status_panel", "-")
val daya =
response.optInt("daya", 0)
val statusDaya =
response.optString("status_daya", "-")
val sumberEnergi =
response.optString("sumber_energi", "-")
val statusSistem =
response.optString("status_sistem", "-")
val statusPompa =
response.optString("status_pompa", "-")
val waktuUpdate =
response.optString("waktu_update", "-")
tvStatusPanel.text = "🟢 $statusPanel"
tvDaya.text = "$daya%"
progressDaya.progress = daya
when {
daya >= 80 -> {
tvStatusDaya.text = "🟢 $statusDaya"
}
daya >= 40 -> {
tvStatusDaya.text = "🟡 $statusDaya"
}
else -> {
tvStatusDaya.text = "🔴 $statusDaya"
}
}
tvSumberEnergi.text =
"🔆 Sumber Energi : $sumberEnergi"
tvStatusSistem.text =
"⚙️ Status Sistem : $statusSistem"
tvStatusPompa.text =
"🚰 Status Pompa : $statusPompa"
tvUpdate.text =
"🕒 Update Terakhir : $waktuUpdate"
},
{ error ->
tvStatusPanel.text = "❌ Gagal mengambil data"
tvDaya.text = "0%"
progressDaya.progress = 0
tvStatusDaya.text = "-"
tvSumberEnergi.text =
"🔆 Sumber Energi : -"
tvStatusSistem.text =
"⚙️ Status Sistem : -"
tvStatusPompa.text =
"🚰 Status Pompa : -"
tvUpdate.text =
"🕒 Update Terakhir : -"
error.printStackTrace()
}
)
Volley.newRequestQueue(this).add(request)
}
}

View File

@ -0,0 +1,344 @@
package com.example.projekta
import android.content.Intent
import android.graphics.Color
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.hivemq.client.mqtt.MqttClient
import com.hivemq.client.mqtt.mqtt3.Mqtt3AsyncClient
import org.json.JSONObject
import kotlin.math.roundToInt
class PemupukanActivity : AppCompatActivity() {
private lateinit var tvSuhuUdara: TextView
private lateinit var tvKelembapanUdara: TextView
private lateinit var tvSuhuTanah: TextView
private lateinit var tvKelembapanTanah: TextView
private lateinit var tvStatusTanah: TextView
private lateinit var tvStatusSistem: TextView
private lateinit var tvStatusPompa: TextView
private lateinit var mqttClient: Mqtt3AsyncClient
private val mqttUser = "DeaBaasithian"
private val mqttPassword = "Lekmamok123#"
private val topicSensor =
"pemupukan/sensor"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(
R.layout.activity_pemupukan
)
val btnBack =
findViewById<ImageView>(
R.id.btnBack
)
val btnMetode =
findViewById<Button>(
R.id.btnMetode
)
tvSuhuUdara =
findViewById(
R.id.tvSuhuUdara
)
tvKelembapanUdara =
findViewById(
R.id.tvKelembapanUdara
)
tvSuhuTanah =
findViewById(
R.id.tvSuhuTanah
)
tvKelembapanTanah =
findViewById(
R.id.tvKelembapanTanah
)
tvStatusTanah =
findViewById(
R.id.tvStatusTanah
)
tvStatusSistem =
findViewById(
R.id.tvStatusSistem
)
tvStatusPompa =
findViewById(
R.id.tvStatusPompa
)
btnBack.setOnClickListener {
finish()
}
btnMetode.setOnClickListener {
startActivity(
Intent(
this,
MetodePemupukanActivity::class.java
)
)
}
tampilDataKosong()
connectMQTT()
}
private fun tampilDataKosong() {
tvSuhuTanah.text =
"🌡️ Suhu Tanah: --"
tvKelembapanTanah.text =
"🌱 Kelembapan Tanah: --"
tvSuhuUdara.text =
"☀️ Suhu Udara: --"
tvKelembapanUdara.text =
"💦 Kelembapan Udara: --"
tvStatusTanah.text =
"🟢 Status Tanah: --"
tvStatusSistem.text =
"⚙️ Menyambungkan..."
tvStatusPompa.text =
"🚰 Status Pompa: --"
}
private fun connectMQTT() {
mqttClient =
MqttClient.builder()
.useMqttVersion3()
.identifier(
"android_" +
System.currentTimeMillis()
)
.serverHost(
"09c34b6317bd4610829ec8a206e9da43.s1.eu.hivemq.cloud"
)
.serverPort(
8883
)
.sslWithDefaultConfig()
.buildAsync()
mqttClient.connectWith()
.simpleAuth()
.username(
mqttUser
)
.password(
mqttPassword.toByteArray()
)
.applySimpleAuth()
.send()
.whenComplete { _, error ->
runOnUiThread {
if (error == null) {
tvStatusSistem.text =
"⚙️ MQTT Connected"
Log.d(
"MQTT",
"CONNECT OK"
)
subscribeSensor()
} else {
tvStatusSistem.text =
"⚙️ Connect Failed"
Log.e(
"MQTT",
error.stackTraceToString()
)
}
}
}
}
private fun subscribeSensor() {
mqttClient.subscribeWith()
.topicFilter(
topicSensor
)
.callback { publish ->
try {
val payload =
String(
publish.payloadAsBytes
)
Log.d(
"MQTT_DATA",
payload
)
val json =
JSONObject(
payload
)
runOnUiThread {
tvSuhuTanah.text =
"🌡️ Suhu Tanah: ${
json.optDouble(
"suhu_tanah",
0.0
).roundToInt()
}°C"
tvKelembapanTanah.text =
"🌱 Kelembapan Tanah: ${
json.optInt(
"kelembapan_tanah",
0
)
}%"
tvSuhuUdara.text =
"☀️ Suhu Udara: ${
json.optDouble(
"suhu_udara",
0.0
).roundToInt()
}°C"
tvKelembapanUdara.text =
"💦 Kelembapan Udara: ${
json.optDouble(
"kelembapan_udara",
0.0
).roundToInt()
}%"
tvStatusTanah.text =
"🟢 Status Tanah: ${
json.optString(
"status_tanah",
"-"
)
}"
val statusPompa =
json.optString(
"status_pompa",
"OFF"
)
tvStatusPompa.text =
"🚰 Status Pompa: $statusPompa"
if (
statusPompa.equals(
"ON",
true
)
) {
tvStatusPompa.setTextColor(
Color.GREEN
)
} else {
tvStatusPompa.setTextColor(
Color.RED
)
}
tvStatusSistem.text =
"⚙️ Data Realtime"
}
} catch (e: Exception) {
Log.e(
"JSON",
e.stackTraceToString()
)
}
}
.send()
.whenComplete { _, error ->
runOnUiThread {
if (error == null) {
Log.d(
"MQTT",
"SUBSCRIBE OK"
)
} else {
tvStatusSistem.text =
"⚙️ Subscribe Failed"
Log.e(
"MQTT",
error.stackTraceToString()
)
}
}
}
}
override fun onDestroy() {
super.onDestroy()
if (::mqttClient.isInitialized) {
mqttClient.disconnect()
}
}
}

View File

@ -0,0 +1,338 @@
package com.example.projekta
import android.Manifest
import android.app.AlertDialog
import android.app.DatePickerDialog
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Bundle
import android.util.Base64
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.content.PermissionChecker
import com.android.volley.toolbox.StringRequest
import com.android.volley.toolbox.Volley
import com.example.projekta.databinding.ActivityProfileBinding
import org.json.JSONObject
import java.io.ByteArrayOutputStream
import java.util.Calendar
class ProfileActivity : AppCompatActivity() {
private lateinit var binding: ActivityProfileBinding
private var bitmapImage: Bitmap? = null
// ===============================
// PILIH FOTO GALERI
// ===============================
private val pickImage =
registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
if (uri != null) {
val inputStream = contentResolver.openInputStream(uri)
bitmapImage = BitmapFactory.decodeStream(inputStream)
binding.imgProfile.setImageBitmap(bitmapImage)
}
}
// ===============================
// CAMERA
// ===============================
private val takePhoto =
registerForActivityResult(ActivityResultContracts.TakePicturePreview()) { bitmap ->
if (bitmap != null) {
bitmapImage = bitmap
binding.imgProfile.setImageBitmap(bitmap)
}
}
// ===============================
// PERMISSION CAMERA
// ===============================
private val requestCameraPermission =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
if (granted) {
takePhoto.launch(null)
} else {
Toast.makeText(this, "Izin kamera ditolak", Toast.LENGTH_SHORT).show()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityProfileBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.btnBack.setOnClickListener {
finish()
}
loadProfile()
binding.imgProfile.setOnClickListener {
showImagePickerDialog()
}
binding.etTanggal.setOnClickListener {
showDatePicker()
}
binding.btnUpdate.setOnClickListener {
updateProfile()
}
}
// ===============================
// LOAD PROFILE
// ===============================
private fun loadProfile() {
val url = "http://192.168.43.191/projekta/profile.php"
val request = object : StringRequest(
Method.POST,
url,
{ response ->
try {
val json = JSONObject(response)
val nama = json.optString("nama")
val email = json.optString("email")
val phone = json.optString("phone")
val tanggal = json.optString("tanggal")
val foto = json.optString("foto").trim()
binding.etNama.setText(nama)
binding.etEmail.setText(email)
binding.etPhone.setText(phone)
binding.etTanggal.setText(tanggal)
binding.txtName.text = nama
binding.txtEmail.text = email
// FOTO
if (foto.isNotEmpty()) {
val decoded = Base64.decode(foto, Base64.DEFAULT)
val bitmap = BitmapFactory.decodeByteArray(
decoded,
0,
decoded.size
)
if (bitmap != null) {
binding.imgProfile.setImageBitmap(bitmap)
}
}
} catch (e: Exception) {
Toast.makeText(this, "Format data error", Toast.LENGTH_SHORT).show()
}
},
{
Toast.makeText(this, "Gagal koneksi server", Toast.LENGTH_SHORT).show()
}
) {
override fun getParams(): MutableMap<String, String> {
val params = HashMap<String, String>()
val email = getSharedPreferences(
"LOGIN",
Context.MODE_PRIVATE
).getString("email", "")
params["email"] = email ?: ""
return params
}
}
Volley.newRequestQueue(this).add(request)
}
// ===============================
// UPDATE PROFILE
// ===============================
private fun updateProfile() {
val url = "http://192.168.43.191/projekta/update_profile.php"
val request = object : StringRequest(
Method.POST,
url,
{ response ->
if (response.contains("success")) {
val namaBaru = binding.etNama.text.toString().trim()
val pref = getSharedPreferences(
"USER_DATA",
Context.MODE_PRIVATE
)
val editor = pref.edit()
editor.putString("nama", namaBaru)
// simpan foto utk sidebar
if (bitmapImage != null) {
val baos = ByteArrayOutputStream()
bitmapImage!!.compress(
Bitmap.CompressFormat.JPEG,
80,
baos
)
val base64Foto = Base64.encodeToString(
baos.toByteArray(),
Base64.NO_WRAP
)
editor.putString("foto", base64Foto)
}
editor.apply()
binding.txtName.text = namaBaru
Toast.makeText(
this,
"Profil berhasil diperbarui",
Toast.LENGTH_SHORT
).show()
} else {
Toast.makeText(
this,
"Gagal update",
Toast.LENGTH_SHORT
).show()
}
},
{
Toast.makeText(this, "Error server", Toast.LENGTH_SHORT).show()
}
) {
override fun getParams(): MutableMap<String, String> {
val params = HashMap<String, String>()
val email = getSharedPreferences(
"LOGIN",
Context.MODE_PRIVATE
).getString("email", "")
params["email"] = email ?: ""
params["nama"] = binding.etNama.text.toString().trim()
params["phone"] = binding.etPhone.text.toString().trim()
params["tanggal"] = binding.etTanggal.text.toString().trim()
if (bitmapImage != null) {
val baos = ByteArrayOutputStream()
bitmapImage!!.compress(
Bitmap.CompressFormat.JPEG,
80,
baos
)
params["foto"] = Base64.encodeToString(
baos.toByteArray(),
Base64.NO_WRAP
)
} else {
params["foto"] = ""
}
return params
}
}
Volley.newRequestQueue(this).add(request)
}
// ===============================
// DATE PICKER
// ===============================
private fun showDatePicker() {
val c = Calendar.getInstance()
DatePickerDialog(
this,
{ _, y, m, d ->
binding.etTanggal.setText(
"$d/${m + 1}/$y"
)
},
c.get(Calendar.YEAR),
c.get(Calendar.MONTH),
c.get(Calendar.DAY_OF_MONTH)
).show()
}
// ===============================
// PILIH FOTO
// ===============================
private fun showImagePickerDialog() {
val pilihan = arrayOf("Galeri", "Kamera")
AlertDialog.Builder(this)
.setTitle("Pilih Foto")
.setItems(pilihan) { _, which ->
when (which) {
0 -> pickImage.launch("image/*")
1 -> openCamera()
}
}
.show()
}
// ===============================
// OPEN CAMERA
// ===============================
private fun openCamera() {
if (
ContextCompat.checkSelfPermission(
this,
Manifest.permission.CAMERA
) == PermissionChecker.PERMISSION_GRANTED
) {
takePhoto.launch(null)
} else {
requestCameraPermission.launch(
Manifest.permission.CAMERA
)
}
}
}

View File

@ -0,0 +1,200 @@
package com.example.projekta
import android.content.Intent
import android.os.Bundle
import android.text.InputType
import android.util.Patterns
import android.view.MotionEvent
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.android.volley.Request
import com.android.volley.toolbox.StringRequest
import com.android.volley.toolbox.Volley
import com.example.projekta.databinding.ActivityRegisterBinding
class RegisterActivity : AppCompatActivity() {
private lateinit var binding: ActivityRegisterBinding
private var isPasswordVisible = false
private var isConfirmPasswordVisible = false
private val url = "http://192.168.43.191/projekta/register.php"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityRegisterBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.btnBack.setOnClickListener {
finish()
}
setupPasswordToggle()
binding.btnRegister.setOnClickListener {
val name = binding.etName.text.toString().trim()
val email = binding.etEmail.text.toString().trim()
val password = binding.etPassword.text.toString()
val confirmPassword = binding.etConfirmPassword.text.toString()
// VALIDASI
if (name.isEmpty()) {
binding.etName.error = "Nama wajib diisi"
return@setOnClickListener
}
if (email.isEmpty() || !Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
binding.etEmail.error = "Email tidak valid"
return@setOnClickListener
}
if (password.length < 6) {
binding.etPassword.error = "Password minimal 6 karakter"
return@setOnClickListener
}
if (password != confirmPassword) {
binding.etConfirmPassword.error = "Password tidak sama"
return@setOnClickListener
}
registerUser(name, email, password)
}
binding.txtLogin.setOnClickListener {
finish()
}
}
private fun registerUser(nama: String, email: String, password: String) {
val request = object : StringRequest(
Request.Method.POST,
url,
{ response ->
if (response.trim() == "success") {
Toast.makeText(this, "Register berhasil", Toast.LENGTH_SHORT).show()
startActivity(Intent(this, LoginActivity::class.java))
finish()
} else {
Toast.makeText(this, "Gagal: $response", Toast.LENGTH_LONG).show()
}
},
{
Toast.makeText(this, "Error koneksi server", Toast.LENGTH_LONG).show()
}
) {
override fun getParams(): MutableMap<String, String> {
val params = HashMap<String, String>()
// 🔥 INI YANG BENAR (HARUS SAMA DENGAN PHP)
params["nama"] = nama
params["email"] = email
params["password"] = password
return params
}
}
Volley.newRequestQueue(this).add(request)
}
private fun setupPasswordToggle() {
binding.etPassword.setOnTouchListener { _, event ->
val drawableEnd = 2
if (event.action == MotionEvent.ACTION_UP) {
val drawable = binding.etPassword.compoundDrawables[drawableEnd]
if (drawable != null &&
event.rawX >= (binding.etPassword.right - drawable.bounds.width())
) {
isPasswordVisible = !isPasswordVisible
if (isPasswordVisible) {
binding.etPassword.inputType =
InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
binding.etPassword.setCompoundDrawablesWithIntrinsicBounds(
R.drawable.ic_lock,
0,
R.drawable.ic_eye_off,
0
)
} else {
binding.etPassword.inputType =
InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
binding.etPassword.setCompoundDrawablesWithIntrinsicBounds(
R.drawable.ic_lock,
0,
R.drawable.ic_eye,
0
)
}
binding.etPassword.setSelection(binding.etPassword.text.length)
return@setOnTouchListener true
}
}
false
}
binding.etConfirmPassword.setOnTouchListener { _, event ->
val drawableEnd = 2
if (event.action == MotionEvent.ACTION_UP) {
val drawable = binding.etConfirmPassword.compoundDrawables[drawableEnd]
if (drawable != null &&
event.rawX >= (binding.etConfirmPassword.right - drawable.bounds.width())
) {
isConfirmPasswordVisible = !isConfirmPasswordVisible
if (isConfirmPasswordVisible) {
binding.etConfirmPassword.inputType =
InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
binding.etConfirmPassword.setCompoundDrawablesWithIntrinsicBounds(
R.drawable.ic_lock,
0,
R.drawable.ic_eye_off,
0
)
} else {
binding.etConfirmPassword.inputType =
InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
binding.etConfirmPassword.setCompoundDrawablesWithIntrinsicBounds(
R.drawable.ic_lock,
0,
R.drawable.ic_eye,
0
)
}
binding.etConfirmPassword.setSelection(binding.etConfirmPassword.text.length)
return@setOnTouchListener true
}
}
false
}
}
}

View File

@ -0,0 +1,28 @@
package com.example.projekta
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.example.projekta.databinding.ActivitySignInBinding
class SignInActivity : AppCompatActivity() {
private lateinit var binding: ActivitySignInBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySignInBinding.inflate(layoutInflater)
setContentView(binding.root)
// 🔥 Tombol Sign In → Login
binding.btnSignIn.setOnClickListener {
startActivity(Intent(this, LoginActivity::class.java))
}
// 🔥 Tombol Create Account → Register
binding.btnRegister.setOnClickListener {
startActivity(Intent(this, RegisterActivity::class.java))
}
}
}

View File

@ -0,0 +1,33 @@
package com.example.projekta
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import androidx.appcompat.app.AppCompatActivity
class SplashActivity : AppCompatActivity() {
private val PREF_NAME = "LOGIN"
private val KEY_LOGIN = "isLogin"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_splash)
Handler(Looper.getMainLooper()).postDelayed({
val sharedPref = getSharedPreferences(PREF_NAME, MODE_PRIVATE)
val isLogin = sharedPref.getBoolean(KEY_LOGIN, false)
if (isLogin) {
startActivity(Intent(this, MenuActivity::class.java))
} else {
startActivity(Intent(this, SignInActivity::class.java))
}
finish()
}, 2000)
}
}

View File

@ -0,0 +1,18 @@
package com.example.projekta
import android.os.Bundle
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
class TentangActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_tentang)
val btnBack = findViewById<ImageView>(R.id.btnBack)
btnBack.setOnClickListener {
finish()
}
}
}

View File

@ -0,0 +1,4 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#2E7D32"/>
<corners android:radius="30dp"/>
</shape>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Warna hijau tua -->
<solid android:color="#2E7D32"/>
<!-- Biar jadi gelembung -->
<corners android:radius="30dp"/>
</shape>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Warna hitam transparan -->
<solid android:color="#33000000"/>
<!-- Sudut melengkung -->
<corners android:radius="12dp"/>
<!-- Border tipis putih -->
<stroke
android:width="1dp"
android:color="#FFFFFF"/>
</shape>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#F2F2F2"/>
<corners android:radius="18dp"/>
</shape>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#2E8E0E"/>
</shape>

View File

@ -0,0 +1,4 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#2E7D32"/>
<corners android:radius="50dp"/>
</shape>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#FFFFFF"/>
<stroke
android:width="2dp"
android:color="#4CAF50"/>
</shape>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF"/>
<corners android:radius="100dp"/>
</shape>

View File

@ -0,0 +1,4 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#A5D6A7"/>
<corners android:radius="16dp"/>
</shape>

View File

@ -0,0 +1,4 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#E8F5E9"/>
<corners android:radius="20dp"/>
</shape>

View File

@ -0,0 +1,4 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#D9E4E6"/>
<corners android:radius="20dp"/>
</shape>

View File

@ -0,0 +1,6 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF"/>
<corners
android:topLeftRadius="40dp"
android:topRightRadius="40dp"/>
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#2E7D32">
<path
android:fillColor="#2E7D32"
android:pathData="M20,4H4C2.9,4 2,4.9 2,6V18C2,19.1 2.9,20 4,20H20C21.1,20 22,19.1 22,18V6C22,4.9 21.1,4 20,4ZM20,8L12,13L4,8V6L12,11L20,6V8Z"/>
</vector>

View File

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#2E7D32">
<path
android:fillColor="#2E7D32"
android:pathData="M12,6C7,6 2.7,9.1 1,12C2.7,14.9 7,18 12,18C17,18 21.3,14.9 23,12C21.3,9.1 17,6 12,6ZM12,16C9.8,16 8,14.2 8,12C8,9.8 9.8,8 12,8C14.2,8 16,9.8 16,12C16,14.2 14.2,16 12,16Z"/>
</vector>

View File

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#2E7D32">
<path
android:fillColor="#2E7D32"
android:pathData="M2,4.27L3.28,3L21,20.72L19.73,22L16.65,18.92C15.17,19.61 13.63,20 12,20C7,20 2.73,16.89 1,12C1.73,9.93 3.06,8.06 4.83,6.61L2,4.27ZM12,8C14.21,8 16,9.79 16,12C16,12.58 15.87,13.13 15.64,13.62L10.38,8.36C10.87,8.13 11.42,8 12,8ZM6.53,8.11L8.08,9.66C8.03,9.87 8,10.08 8,10.3C8,12.51 9.79,14.3 12,14.3C12.22,14.3 12.43,14.27 12.64,14.22L14.19,15.77C13.53,16.13 12.79,16.3 12,16.3C9.24,16.3 7,14.06 7,11.3C7,10.51 7.17,9.77 7.53,9.11L6.53,8.11Z"/>
</vector>

View File

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View File

@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View File

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#2E7D32">
<path
android:fillColor="#2E7D32"
android:pathData="M12,2C9.79,2 8,3.79 8,6V8H6C4.9,8 4,8.9 4,10V20C4,21.1 4.9,22 6,22H18C19.1,22 20,21.1 20,20V10C20,8.9 19.1,8 18,8H16V6C16,3.79 14.21,2 12,2ZM12,4C13.1,4 14,4.9 14,6V8H10V6C10,4.9 10.9,4 12,4ZM12,17C10.9,17 10,16.1 10,15C10,13.9 10.9,13 12,13C13.1,13 14,13.9 14,15C14,16.1 13.1,17 12,17Z"/>
</vector>

View File

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#2E7D32">
<path
android:fillColor="#2E7D32"
android:pathData="M12,12C14.21,12 16,10.21 16,8C16,5.79 14.21,4 12,4C9.79,4 8,5.79 8,8C8,10.21 9.79,12 12,12ZM12,14C9.33,14 4,15.34 4,18V20H20V18C20,15.34 14.67,14 12,14Z"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#F5F5F5">
<!-- HEADER -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="70dp"
android:background="#43A047"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp">
<!-- BUTTON BACK -->
<ImageView
android:id="@+id/btnBack"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@android:drawable/ic_media_previous"
app:tint="#FFFFFF" />
<!-- TITLE -->
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Histori Pemupukan"
android:textColor="#FFFFFF"
android:textStyle="bold"
android:textSize="18sp"
android:gravity="center" />
</LinearLayout>
<!-- JUDUL -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Histori Pemupukan"
android:textColor="#2E7D32"
android:textStyle="bold"
android:textSize="24sp"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="12dp" />
<!-- RECYCLER VIEW -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerHistori"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:paddingBottom="20dp"/>
</LinearLayout>

View File

@ -0,0 +1,139 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F5F5F5">
<!-- TOP IMAGE -->
<ImageView
android:id="@+id/imgTop"
android:layout_width="0dp"
android:layout_height="250dp"
android:scaleType="centerCrop"
android:src="@drawable/temakopi"
android:contentDescription="background"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<!-- BACK BUTTON -->
<ImageView
android:id="@+id/btnBack"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@android:drawable/ic_media_previous"
android:background="@drawable/bg_circle_white"
android:padding="8dp"
app:tint="#2E7D32"
android:elevation="4dp"
android:contentDescription="back"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:layout_margin="16dp"/>
<!-- CONTAINER -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="vertical"
android:padding="24dp"
android:background="@drawable/bg_top_curve"
app:layout_constraintTop_toBottomOf="@id/imgTop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<!-- TITLE -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Selamat Datang"
android:textSize="26sp"
android:textStyle="bold"
android:textColor="#2E7D32"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Masuk ke akun anda"
android:textSize="14sp"
android:textColor="#888888"
android:layout_marginBottom="24dp"/>
<!-- EMAIL -->
<EditText
android:id="@+id/etEmail"
android:layout_width="match_parent"
android:layout_height="55dp"
android:hint="Email"
android:inputType="textEmailAddress"
android:drawableStart="@drawable/ic_email"
android:drawablePadding="10dp"
android:padding="14dp"
android:textColor="#2E7D32"
android:textColorHint="#7A9E7E"
android:background="@drawable/bg_input_round"
android:layout_marginBottom="12dp"/>
<!-- PASSWORD -->
<EditText
android:id="@+id/etPassword"
android:layout_width="match_parent"
android:layout_height="55dp"
android:hint="Password"
android:inputType="textPassword"
android:drawableStart="@drawable/ic_lock"
android:drawableEnd="@drawable/ic_eye"
android:drawablePadding="10dp"
android:padding="14dp"
android:textColor="#2E7D32"
android:textColorHint="#7A9E7E"
android:background="@drawable/bg_input_round"/>
<!-- REMEMBER -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="10dp">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Remember Me"
android:textSize="12sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Lupa password?"
android:textSize="12sp"
android:textColor="#2E7D32"
android:layout_marginStart="16dp"/>
</LinearLayout>
<!-- LOGIN BUTTON -->
<com.google.android.material.button.MaterialButton
android:id="@+id/btnLogin"
android:layout_width="match_parent"
android:layout_height="55dp"
android:text="Login"
android:textColor="#FFFFFF"
android:layout_marginTop="24dp"
app:backgroundTint="#2E7D32"
app:cornerRadius="30dp"/>
<!-- REGISTER -->
<TextView
android:id="@+id/txtRegister"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Belum punya akun? Register"
android:textSize="13sp"
android:layout_marginTop="16dp"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,280 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- ================= MAIN CONTENT ================= -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#F5F5F5">
<!-- HEADER -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#4CAF50"
android:orientation="horizontal"
android:gravity="center_vertical"
android:padding="16dp">
<ImageView
android:id="@+id/btnMenu"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@android:drawable/ic_menu_sort_by_size"
app:tint="#FFFFFF"
android:contentDescription="Menu"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Beranda"
android:textSize="20sp"
android:textStyle="bold"
android:textColor="#FFFFFF"
android:layout_marginStart="16dp"/>
</LinearLayout>
<!-- TITLE -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Apa yang ingin anda lihat?"
android:textSize="18sp"
android:textStyle="bold"
android:padding="16dp"/>
<!-- MENU LIST -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp">
<!-- PEMUPUKAN -->
<LinearLayout
android:id="@+id/menuPemupukan"
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="@drawable/bg_menu_item"
android:orientation="horizontal"
android:gravity="center_vertical"
android:padding="16dp"
android:layout_marginBottom="12dp"
android:clickable="true"
android:focusable="true">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/pupuk"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pemupukan"
android:textSize="16sp"
android:layout_marginStart="16dp"/>
</LinearLayout>
<!-- PANDUAN -->
<LinearLayout
android:id="@+id/menuPanduan"
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="@drawable/bg_menu_item"
android:orientation="horizontal"
android:gravity="center_vertical"
android:padding="16dp"
android:layout_marginBottom="12dp"
android:clickable="true"
android:focusable="true">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/sensor"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Panduan Pengoperasian"
android:textSize="16sp"
android:layout_marginStart="16dp"/>
</LinearLayout>
<!-- PANEL SURYA -->
<LinearLayout
android:id="@+id/menuPanelSurya"
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="@drawable/bg_menu_item"
android:orientation="horizontal"
android:gravity="center_vertical"
android:padding="16dp"
android:layout_marginBottom="12dp"
android:clickable="true"
android:focusable="true">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/solarpanel"
android:contentDescription="Panel Surya"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Panel Surya"
android:textSize="16sp"
android:layout_marginStart="16dp"/>
</LinearLayout>
<!-- TENTANG -->
<LinearLayout
android:id="@+id/menuTentang"
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="@drawable/bg_menu_item"
android:orientation="horizontal"
android:gravity="center_vertical"
android:padding="16dp"
android:layout_marginBottom="12dp"
android:clickable="true"
android:focusable="true">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/panduan"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tentang Aplikasi"
android:textSize="16sp"
android:layout_marginStart="16dp"/>
</LinearLayout>
<!-- HISTORI -->
<LinearLayout
android:id="@+id/menuHistori"
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="@drawable/bg_menu_item"
android:orientation="horizontal"
android:gravity="center_vertical"
android:padding="16dp"
android:clickable="true"
android:focusable="true">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/histori"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Histori Sensor"
android:textSize="16sp"
android:layout_marginStart="16dp"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<!-- ================= SIDEBAR ================= -->
<LinearLayout
android:id="@+id/sidebar"
android:layout_width="280dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:orientation="vertical"
android:background="#FFFFFF">
<!-- HEADER SIDEBAR -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="120dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:padding="16dp"
android:background="#7ED957">
<ImageView
android:id="@+id/imgSidebarProfile"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@drawable/profileman"
android:scaleType="centerCrop"
android:background="@drawable/bg_circle_white"
android:padding="2dp"
android:contentDescription="Foto Profil"/>
<TextView
android:id="@+id/txtSidebarName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Nama Pengguna"
android:textColor="#FFFFFF"
android:textSize="16sp"
android:textStyle="bold"
android:layout_marginStart="12dp"/>
</LinearLayout>
<!-- PROFILE -->
<LinearLayout
android:id="@+id/menuProfile"
android:layout_width="match_parent"
android:layout_height="60dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:padding="16dp"
android:clickable="true"
android:focusable="true">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/iconprofil"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Profile"
android:layout_marginStart="16dp"/>
</LinearLayout>
<!-- LOGOUT -->
<LinearLayout
android:id="@+id/menuLogout"
android:layout_width="match_parent"
android:layout_height="60dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:padding="16dp"
android:clickable="true"
android:focusable="true">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/logout"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Logout"
android:layout_marginStart="16dp"/>
</LinearLayout>
</LinearLayout>
</androidx.drawerlayout.widget.DrawerLayout>

View File

@ -0,0 +1,201 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F4F6F8">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/header"
android:layout_width="0dp"
android:layout_height="70dp"
android:background="#2E8B57"
android:gravity="center_vertical"
android:padding="16dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<ImageView
android:id="@+id/btnBack"
android:layout_width="26dp"
android:layout_height="26dp"
android:contentDescription="Back"
android:src="@android:drawable/ic_media_previous"
app:tint="#FFFFFF" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Pengaturan Pemupukan"
android:textColor="#FFFFFF"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
<androidx.cardview.widget.CardView
android:id="@+id/cardAuto"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="16dp"
app:cardCornerRadius="18dp"
app:cardElevation="10dp"
app:layout_constraintTop_toBottomOf="@id/header"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="18dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="MODE OTOMATIS"
android:textColor="#2E8B57"
android:textSize="18sp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@android:drawable/ic_lock_idle_alarm" />
<TextView
android:id="@+id/tvJam"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:text="07:00:00"
android:textSize="16sp" />
</LinearLayout>
<Button
android:id="@+id/btnPilihJam"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:backgroundTint="#2E8B57"
android:text="Ubah Jam"
android:textColor="#FFFFFF" />
<!-- Interval -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="18dp"
android:text="Interval Pemupukan (Hari)"
android:textStyle="bold" />
<EditText
android:id="@+id/etInterval"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="6dp"
android:hint="Contoh: 14"
android:inputType="number" />
<!-- Durasi -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="18dp"
android:text="Durasi Penyiraman (Detik)"
android:textStyle="bold" />
<EditText
android:id="@+id/etDurasi"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="6dp"
android:hint="Contoh: 20"
android:inputType="number" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/cardManual"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="16dp"
app:cardCornerRadius="18dp"
app:cardElevation="6dp"
app:layout_constraintTop_toBottomOf="@id/cardAuto"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="18dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="MODE MANUAL"
android:textColor="#D32F2F"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tvStatusManual"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="STATUS : OFF"
android:textColor="#D32F2F"
android:textSize="16sp"
android:textStyle="bold" />
<Button
android:id="@+id/btnPompaManual"
android:layout_width="match_parent"
android:layout_height="55dp"
android:layout_marginTop="12dp"
android:backgroundTint="#00C853"
android:text="NYALAKAN POMPA"
android:textColor="#FFFFFF" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<Button
android:id="@+id/btnSimpan"
android:layout_width="0dp"
android:layout_height="55dp"
android:layout_margin="16dp"
android:backgroundTint="#2E8B57"
android:text="SIMPAN PENGATURAN"
android:textColor="#FFFFFF"
android:textStyle="bold"
app:layout_constraintTop_toBottomOf="@id/cardManual"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

View File

@ -0,0 +1,207 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:background="#55C216">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="20dp">
<!-- HEADER -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="80dp"
android:paddingStart="12dp"
android:paddingEnd="12dp">
<ImageView
android:id="@+id/btnBack"
android:layout_width="38dp"
android:layout_height="38dp"
android:layout_centerVertical="true"
android:padding="8dp"
android:src="@android:drawable/ic_media_previous"
app:tint="#FFFFFF" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Panduan"
android:textColor="#FFFFFF"
android:textStyle="bold"
android:textSize="28sp" />
</RelativeLayout>
<!-- CARD 1 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="#EDEDED"
android:orientation="horizontal"
android:padding="18dp">
<ImageView
android:layout_width="42dp"
android:layout_height="42dp"
android:layout_gravity="center_vertical"
android:src="@android:drawable/ic_lock_power_off"
app:tint="#0A8F3D"/>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="14dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hidupkan Alat"
android:textStyle="bold"
android:textSize="20sp"
android:textColor="#222222"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:text="Sambungkan perangkat ke listrik/USB atau tekan tombol power. Pastikan lampu indikator menyala sebagai tanda alat aktif."
android:textSize="16sp"
android:textColor="#222222"/>
</LinearLayout>
</LinearLayout>
<!-- CARD 2 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:background="#EDEDED"
android:orientation="horizontal"
android:padding="18dp">
<ImageView
android:layout_width="42dp"
android:layout_height="42dp"
android:layout_gravity="center_vertical"
android:src="@android:drawable/ic_menu_compass"
app:tint="#0A8F3D"/>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="14dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Sensor Membaca Data"
android:textStyle="bold"
android:textSize="20sp"
android:textColor="#222222"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:text="Secara otomatis sensor akan mengukur kelembapan tanah, suhu udara, kelembapan udara."
android:textSize="16sp"
android:textColor="#222222"/>
</LinearLayout>
</LinearLayout>
<!-- CARD 3 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="#EDEDED"
android:orientation="horizontal"
android:padding="18dp">
<ImageView
android:layout_width="42dp"
android:layout_height="42dp"
android:layout_gravity="center_vertical"
android:src="@android:drawable/ic_menu_upload"
app:tint="#0A8F3D"/>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="14dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Data Terkirim Via Iot"
android:textStyle="bold"
android:textSize="20sp"
android:textColor="#222222"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:text="Hasil pengukuran dikirim melalui Wi-Fi/internet ke server aplikasi."
android:textSize="16sp"
android:textColor="#222222"/>
</LinearLayout>
</LinearLayout>
<!-- CARD 4 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="#EDEDED"
android:orientation="horizontal"
android:padding="18dp">
<ImageView
android:layout_width="42dp"
android:layout_height="42dp"
android:layout_gravity="center_vertical"
android:src="@android:drawable/ic_menu_view"
app:tint="#0A8F3D"/>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="14dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Lihat Di Aplikasi"
android:textStyle="bold"
android:textSize="20sp"
android:textColor="#222222"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:text="Buka aplikasi di smartphone. Data terbaru tampil di Dashboard dan histori dapat dilihat di menu sensor."
android:textSize="16sp"
android:textColor="#222222"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>

View File

@ -0,0 +1,216 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F5F5F5">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- HEADER -->
<LinearLayout
android:id="@+id/header"
android:layout_width="0dp"
android:layout_height="70dp"
android:background="#2E8B57"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingHorizontal="16dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<ImageView
android:id="@+id/btnBack"
android:layout_width="28dp"
android:layout_height="28dp"
android:src="@android:drawable/ic_media_previous"
android:contentDescription="Back"
app:tint="@android:color/white"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="Monitoring Panel Surya"
android:textColor="@android:color/white"
android:textStyle="bold"
android:textSize="18sp"
android:paddingEnd="28dp"/>
</LinearLayout>
<!-- HEADER IMAGE -->
<ImageView
android:id="@+id/imgHeader"
android:layout_width="0dp"
android:layout_height="180dp"
android:scaleType="centerCrop"
android:src="@drawable/panel"
app:layout_constraintTop_toBottomOf="@id/header"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<!-- JUDUL -->
<TextView
android:id="@+id/titleImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="☀️ Panel Surya"
android:textColor="@android:color/white"
android:textStyle="bold"
android:textSize="24sp"
android:layout_marginStart="20dp"
android:layout_marginTop="28dp"
app:layout_constraintStart_toStartOf="@id/imgHeader"
app:layout_constraintTop_toTopOf="@id/imgHeader"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Monitoring Daya Sistem"
android:textColor="@android:color/white"
android:textSize="15sp"
android:layout_marginStart="20dp"
android:layout_marginTop="6dp"
app:layout_constraintTop_toBottomOf="@id/titleImage"
app:layout_constraintStart_toStartOf="@id/imgHeader"/>
<!-- CARD -->
<androidx.cardview.widget.CardView
android:id="@+id/cardPanel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="20dp"
android:layout_marginTop="-30dp"
app:cardCornerRadius="16dp"
app:cardElevation="6dp"
app:layout_constraintTop_toBottomOf="@id/imgHeader"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="18dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Status Panel"
android:textStyle="bold"
android:textSize="16sp"/>
<TextView
android:id="@+id/tvStatusPanel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="🟢 Aktif"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="#2E8B57"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#DDDDDD"
android:layout_marginVertical="12dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cek Daya"
android:textStyle="bold"/>
<TextView
android:id="@+id/tvDaya"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="95%"
android:textSize="30sp"
android:textStyle="bold"
android:textColor="#2E8B57"/>
<ProgressBar
android:id="@+id/progressDaya"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="12dp"
android:max="100"
android:progress="95"
android:layout_marginTop="8dp"/>
<TextView
android:id="@+id/tvStatusDaya"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="🟢 Sangat Baik"
android:textStyle="bold"
android:textColor="#2E8B57"
android:layout_marginTop="10dp"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#DDDDDD"
android:layout_marginVertical="12dp"/>
<TextView
android:id="@+id/tvSumberEnergi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="🔆 Sumber Energi : Panel Surya 5 Wp"/>
<TextView
android:id="@+id/tvStatusSistem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="⚙️ Status Sistem : Aktif"
android:layout_marginTop="10dp"/>
<TextView
android:id="@+id/tvStatusPompa"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="🚰 Status Pompa : OFF"
android:layout_marginTop="10dp"/>
<TextView
android:id="@+id/tvUpdate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="🕒 Update Terakhir : -"
android:layout_marginTop="10dp"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<Button
android:id="@+id/btnRefresh"
android:layout_width="0dp"
android:layout_height="55dp"
android:layout_marginHorizontal="20dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="30dp"
android:text="REFRESH DATA"
android:textColor="@android:color/white"
android:textStyle="bold"
android:backgroundTint="#2E8B57"
app:layout_constraintTop_toBottomOf="@id/cardPanel"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

View File

@ -0,0 +1,200 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F5F5F5">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- HEADER -->
<LinearLayout
android:id="@+id/header"
android:layout_width="0dp"
android:layout_height="70dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:background="#2E8B57"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<ImageView
android:id="@+id/btnBack"
android:layout_width="28dp"
android:layout_height="28dp"
android:contentDescription="Back"
android:padding="2dp"
android:src="@android:drawable/ic_media_previous"
app:tint="#FFFFFF" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:paddingEnd="28dp"
android:text="Smart Fertilizer System"
android:textColor="#FFFFFF"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
<!-- IMAGE -->
<ImageView
android:id="@+id/imgHeader"
android:layout_width="0dp"
android:layout_height="180dp"
android:scaleType="centerCrop"
android:src="@drawable/kebunkopi"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/header" />
<!-- TITLE -->
<TextView
android:id="@+id/titleImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="30dp"
android:text="Smart Fertilizer System"
android:textColor="#FFFFFF"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="@id/imgHeader"
app:layout_constraintTop_toTopOf="@id/imgHeader" />
<TextView
android:id="@+id/subTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="8dp"
android:text="Tanaman: Kopi / Kakao"
android:textColor="#FFFFFF"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="@id/imgHeader"
app:layout_constraintTop_toBottomOf="@id/titleImage" />
<!-- CARD STATUS -->
<androidx.cardview.widget.CardView
android:id="@+id/cardStatus"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="-30dp"
android:layout_marginEnd="20dp"
app:cardCornerRadius="16dp"
app:cardElevation="6dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/imgHeader">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/tvSuhuTanah"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="🌡️ Suhu Tanah: --"
android:textColor="#333333"
android:textSize="16sp" />
<TextView
android:id="@+id/tvKelembapanTanah"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="🌱 Kelembapan Tanah: --"
android:textColor="#333333"
android:textSize="16sp" />
<TextView
android:id="@+id/tvSuhuUdara"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="☀️ Suhu Udara: --"
android:textColor="#333333"
android:textSize="16sp" />
<TextView
android:id="@+id/tvKelembapanUdara"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="💦 Kelembapan Udara: --"
android:textColor="#333333"
android:textSize="16sp" />
<TextView
android:id="@+id/tvStatusTanah"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="🟢 Status Tanah: --"
android:textColor="#2E8B57"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tvStatusSistem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="⚙️ Status Sistem: --"
android:textColor="#2E8B57"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tvStatusPompa"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="🚰 Status Pompa: --"
android:textColor="#2E8B57"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<!-- BUTTON PENGATURAN -->
<Button
android:id="@+id/btnMetode"
android:layout_width="0dp"
android:layout_height="55dp"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="30dp"
android:backgroundTint="#2E8B57"
android:text="PENGATURAN PEMUPUKAN"
android:textColor="#FFFFFF"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cardStatus" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

View File

@ -0,0 +1,111 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F5F5F5">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp">
<!-- BACK -->
<ImageView
android:id="@+id/btnBack"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@android:drawable/ic_media_previous"
android:padding="8dp"
android:background="@drawable/bg_circle_green"
app:tint="#FFFFFF" />
<!-- PROFILE IMAGE -->
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/imgProfile"
android:layout_width="110dp"
android:layout_height="110dp"
android:layout_gravity="center"
android:layout_marginTop="20dp"
android:src="@drawable/profileman"
app:civ_border_width="3dp"
app:civ_border_color="#4CAF50" />
<!-- NAME -->
<TextView
android:id="@+id/txtName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Nama"
android:textSize="18sp"
android:textStyle="bold"
android:layout_gravity="center"
android:layout_marginTop="10dp"/>
<!-- EMAIL DISPLAY -->
<TextView
android:id="@+id/txtEmail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="email@gmail.com"
android:layout_gravity="center"
android:textColor="#888888"
android:layout_marginBottom="20dp"/>
<!-- INPUT NAMA -->
<EditText
android:id="@+id/etNama"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="Nama"
android:padding="12dp"
android:background="@android:drawable/edit_text"
android:layout_marginBottom="10dp"/>
<!-- EMAIL (READ ONLY) -->
<EditText
android:id="@+id/etEmail"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="Email"
android:padding="12dp"
android:background="@android:drawable/edit_text"
android:enabled="false"
android:layout_marginBottom="10dp"/>
<!-- PHONE -->
<EditText
android:id="@+id/etPhone"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="Phone"
android:padding="12dp"
android:background="@android:drawable/edit_text"
android:inputType="phone"
android:layout_marginBottom="10dp"/>
<!-- TANGGAL -->
<EditText
android:id="@+id/etTanggal"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="Tanggal Lahir"
android:padding="12dp"
android:background="@android:drawable/edit_text"
android:focusable="false"
android:clickable="true"
android:layout_marginBottom="20dp"/>
<!-- BUTTON -->
<Button
android:id="@+id/btnUpdate"
android:layout_width="match_parent"
android:layout_height="55dp"
android:text="Perbarui Profil"
android:textColor="#FFFFFF"
android:background="@drawable/bg_button_login"/>
</LinearLayout>
</ScrollView>

View File

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F5F5F5">
<!-- TOP IMAGE -->
<ImageView
android:id="@+id/imgTop"
android:layout_width="0dp"
android:layout_height="250dp"
android:scaleType="centerCrop"
android:src="@drawable/temakopi"
android:contentDescription="background"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<!-- BACK BUTTON -->
<ImageView
android:id="@+id/btnBack"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@android:drawable/ic_media_previous"
android:background="@drawable/bg_circle_white"
android:padding="8dp"
app:tint="#2E7D32"
android:elevation="4dp"
android:contentDescription="back"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:layout_margin="16dp"/>
<!-- CONTAINER -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="vertical"
android:padding="24dp"
android:background="@drawable/bg_top_curve"
app:layout_constraintTop_toBottomOf="@id/imgTop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<!-- TITLE -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Create Account"
android:textSize="26sp"
android:textStyle="bold"
android:textColor="#2E7D32"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Daftar akun baru"
android:textSize="14sp"
android:textColor="#888888"
android:layout_marginBottom="24dp"/>
<!-- FULL NAME -->
<EditText
android:id="@+id/etName"
android:layout_width="match_parent"
android:layout_height="55dp"
android:hint="Full Name"
android:inputType="textPersonName"
android:drawableStart="@drawable/ic_user"
android:drawablePadding="10dp"
android:padding="14dp"
android:textColor="#2E7D32"
android:textColorHint="#7A9E7E"
android:background="@drawable/bg_input_round"
android:layout_marginBottom="12dp"/>
<!-- EMAIL -->
<EditText
android:id="@+id/etEmail"
android:layout_width="match_parent"
android:layout_height="55dp"
android:hint="Email"
android:inputType="textEmailAddress"
android:drawableStart="@drawable/ic_email"
android:drawablePadding="10dp"
android:padding="14dp"
android:textColor="#2E7D32"
android:textColorHint="#7A9E7E"
android:background="@drawable/bg_input_round"
android:layout_marginBottom="12dp"/>
<!-- PASSWORD -->
<EditText
android:id="@+id/etPassword"
android:layout_width="match_parent"
android:layout_height="55dp"
android:hint="Password"
android:inputType="textPassword"
android:drawableStart="@drawable/ic_lock"
android:drawableEnd="@drawable/ic_eye"
android:drawablePadding="10dp"
android:padding="14dp"
android:textColor="#2E7D32"
android:textColorHint="#7A9E7E"
android:background="@drawable/bg_input_round"
android:layout_marginBottom="12dp"/>
<!-- CONFIRM PASSWORD -->
<EditText
android:id="@+id/etConfirmPassword"
android:layout_width="match_parent"
android:layout_height="55dp"
android:hint="Confirm Password"
android:inputType="textPassword"
android:drawableStart="@drawable/ic_lock"
android:drawableEnd="@drawable/ic_eye"
android:drawablePadding="10dp"
android:padding="14dp"
android:textColor="#2E7D32"
android:textColorHint="#7A9E7E"
android:background="@drawable/bg_input_round"/>
<!-- BUTTON REGISTER -->
<com.google.android.material.button.MaterialButton
android:id="@+id/btnRegister"
android:layout_width="match_parent"
android:layout_height="55dp"
android:text="Register"
android:textColor="#FFFFFF"
android:layout_marginTop="24dp"
app:backgroundTint="#2E7D32"
app:cornerRadius="30dp"/>
<!-- LOGIN LINK -->
<TextView
android:id="@+id/txtLogin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Sudah punya akun? Login"
android:textSize="13sp"
android:layout_marginTop="16dp"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Background -->
<ImageView
android:layout_width="0dp"
android:layout_height="0dp"
android:src="@drawable/temakopi"
android:scaleType="centerCrop"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<!-- Overlay -->
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#55000000"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<!-- Title kiri atas -->
<TextView
android:id="@+id/txtTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="KopiKaoCare\nSmart Care for\nCoffee &amp; Cocoa"
android:textColor="#FFFFFF"
android:textSize="28sp"
android:textStyle="bold"
android:lineSpacingExtra="6dp"
android:layout_marginTop="60dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<!-- Container tombol -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
android:layout_marginStart="40dp"
android:layout_marginEnd="40dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<!-- Sign In -->
<Button
android:id="@+id/btnSignIn"
android:layout_width="match_parent"
android:layout_height="55dp"
android:text="Sign In"
android:textColor="#FFFFFF"
android:textSize="16sp"
android:background="@drawable/bg_button_transparent"/>
<!-- Create Account -->
<Button
android:id="@+id/btnRegister"
android:layout_width="match_parent"
android:layout_height="55dp"
android:text="Create Account"
android:textColor="#FFFFFF"
android:textSize="16sp"
android:background="@drawable/bg_button_transparent"
android:layout_marginTop="16dp"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F3E5AB">
<ImageView
android:id="@+id/imgKopi"
android:layout_width="150dp"
android:layout_height="150dp"
android:src="@drawable/kopikao"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<TextView
android:id="@+id/txtApp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="KopiKaoCare"
android:textSize="22sp"
android:textStyle="bold"
android:textColor="#000000"
app:layout_constraintTop_toBottomOf="@id/imgKopi"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="16dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#44BE16">
<!-- Tombol Back Bulat -->
<ImageView
android:id="@+id/btnBack"
android:layout_width="38dp"
android:layout_height="38dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:background="@drawable/bg_circle_back"
android:padding="8dp"
android:src="@android:drawable/ic_media_previous"
app:tint="#FFFFFF"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<!-- Judul -->
<TextView
android:id="@+id/txtTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tentang Aplikasi"
android:textColor="#FFFFFF"
android:textSize="22sp"
android:textStyle="bold"
android:layout_marginTop="44dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<!-- Card Putih -->
<androidx.core.widget.NestedScrollView
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="18dp"
android:layout_marginEnd="18dp"
android:layout_marginTop="28dp"
android:layout_marginBottom="18dp"
android:fillViewport="true"
app:layout_constraintTop_toBottomOf="@id/txtTitle"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_card_tentang"
android:orientation="vertical"
android:padding="14dp">
<!-- Logo -->
<ImageView
android:layout_width="140dp"
android:layout_height="90dp"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:src="@drawable/logokopi"/>
<!-- Isi Text -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text='KopiKaoCare adalah aplikasi berbasis IoT yang dirancang untuk mengontrol dan memantau sistem pemupukan otomatis pada tanaman kopi dan kakao.&#10;&#10;Aplikasi ini membaca kelembapan tanah secara real-time untuk menentukan waktu pemupukan yang tepat, sehingga pupuk diberikan sesuai kebutuhan tanaman. Dengan sistem otomatis berbasis tenaga surya, pemupukan menjadi lebih efisien, tepat dosis, dan ramah lingkungan.&#10;&#10;Dengan KopiKaoCare, petani dapat:&#10;• Memastikan kondisi tanah dan udara tetap ideal bagi pertumbuhan tanaman kopi dan kakao.&#10;• Mencegah risiko kekeringan atau kelembapan berlebih yang dapat menurunkan kualitas dan produktivitas tanaman.&#10;• Mengontrol sistem pemupukan otomatis secara manual maupun otomatis sesuai kebutuhan tanaman.&#10;• Mendukung pertanian yang lebih efisien, cerdas, dan berkelanjutan melalui pemanfaatan teknologi IoT dan energi terbarukan (panel surya).&#10;&#10;KopiKaoCare hadir sebagai solusi inovatif untuk meningkatkan efisiensi pemupukan, mengurangi kesalahan manual, serta mendukung sistem pertanian presisi demi ketahanan pangan yang lebih baik.'
android:textColor="#222222"
android:textSize="16sp"
android:lineSpacingExtra="4dp"
android:fontFamily="serif"
android:layout_marginTop="10dp"/>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/cardHistori"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
app:cardCornerRadius="14dp"
app:cardElevation="3dp"
app:cardBackgroundColor="#FFFFFF">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="18dp">
<!-- TANGGAL -->
<TextView
android:id="@+id/tvTanggal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="20 Feb 2026"
android:textStyle="bold"
android:textSize="18sp"
android:textColor="#2E7D32" />
<!-- JAM -->
<TextView
android:id="@+id/tvJam"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="07:00 WIB"
android:textSize="15sp"
android:textColor="#555555"
android:layout_marginTop="8dp" />
<!-- MODE -->
<TextView
android:id="@+id/tvMode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="• Mode: Otomatis"
android:textStyle="bold"
android:textColor="#444444"
android:textSize="16sp"
android:layout_marginTop="12dp" />
<!-- DURASI -->
<TextView
android:id="@+id/tvDurasi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="• Durasi: 20 Detik"
android:textColor="#555555"
android:textSize="16sp"
android:layout_marginTop="8dp" />
<!-- INTERVAL -->
<TextView
android:id="@+id/tvInterval"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="• Interval: 14 Hari"
android:textColor="#555555"
android:textSize="16sp"
android:layout_marginTop="8dp" />
<!-- STATUS TANAH -->
<TextView
android:id="@+id/tvStatusTanah"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="🔥 Status Tanah: Kering"
android:textStyle="bold"
android:textColor="#C49000"
android:textSize="15sp"
android:layout_marginTop="10dp" />
</LinearLayout>
</androidx.cardview.widget.CardView>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -0,0 +1,7 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Base.Theme.ProjekTA" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Customize your dark theme here. -->
<!-- <item name="colorPrimary">@color/my_dark_primary</item> -->
</style>
</resources>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>

View File

@ -0,0 +1,30 @@
<resources>
<!-- APP -->
<string name="app_name">Coffee App</string>
<!-- LOGIN / REGISTER -->
<string name="sign_in_button">Sign In</string>
<string name="register_button">Buat Akun</string>
<!-- ================= PEMUPUKAN ================= -->
<string name="back_button">Kembali</string>
<string name="title_pengaturan">Pengaturan Pemupukan</string>
<string name="mode_otomatis">MODE OTOMATIS</string>
<string name="mode_manual">MODE MANUAL</string>
<string name="jam_default">⏰ Jam: 07:00 WIB</string>
<string name="ubah_jam">Ubah Jam</string>
<string name="interval_default">📅 Setiap 14 Hari</string>
<string name="durasi_label">⏱️ Durasi Penyiraman</string>
<string name="status_off">STATUS: OFF</string>
<string name="aktifkan_pompa">AKTIFKAN POMPA</string>
<string name="simpan_pengaturan">SIMPAN PENGATURAN</string>
</resources>

View File

@ -0,0 +1,31 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base -->
<style name="Base.Theme.ProjekTA" parent="Theme.Material3.DayNight.NoActionBar">
<!-- 🔥 WARNA UTAMA JADI HIJAU -->
<item name="colorPrimary">#2E7D32</item>
<item name="colorOnPrimary">#FFFFFF</item>
<item name="colorSecondary">#2E7D32</item>
<item name="colorOnSecondary">#FFFFFF</item>
<!-- Optional biar konsisten -->
<item name="colorPrimaryContainer">#A5D6A7</item>
<item name="colorOnPrimaryContainer">#1B5E20</item>
</style>
<!-- Main -->
<style name="Theme.ProjekTA" parent="Base.Theme.ProjekTA" />
<!-- SPLASH -->
<style name="Theme.ProjekTA.Splash" parent="Theme.Material3.DayNight.NoActionBar">
<item name="android:windowSplashScreenBackground">#FFFFFF</item>
<item name="android:windowSplashScreenAnimatedIcon">@drawable/kopikao</item>
<item name="postSplashScreenTheme">@style/Theme.ProjekTA</item>
</style>
</resources>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample backup rules file; uncomment and customize as necessary.
See https://developer.android.com/guide/topics/data/autobackup
for details.
Note: This file is ignored for devices older than API 31
See https://developer.android.com/about/versions/12/backup-restore
-->
<full-backup-content>
<!--
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="device.xml"/>
-->
</full-backup-content>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample data extraction rules file; uncomment and customize as necessary.
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
for details.
-->
<data-extraction-rules>
<cloud-backup>
<!-- TODO: Use <include> and <exclude> to control what is backed up.
<include .../>
<exclude .../>
-->
</cloud-backup>
<!--
<device-transfer>
<include .../>
<exclude .../>
</device-transfer>
-->
</data-extraction-rules>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config
cleartextTrafficPermitted="true">
<trust-anchors>
<certificates
src="system"/>
</trust-anchors>
</base-config>
</network-security-config>

View File

@ -0,0 +1,17 @@
package com.example.projekta
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}

4
build.gradle.kts Normal file
View File

@ -0,0 +1,4 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
alias(libs.plugins.android.application) apply false
}

Some files were not shown because too many files have changed in this diff Show More