Compare commits

...

24 Commits

Author SHA1 Message Date
152b9f64c6 fix 2026-01-12 17:40:45 +07:00
34edb0abc3 fix 2026-01-12 17:39:53 +07:00
2cc0e94057 fix 2026-01-12 17:30:25 +07:00
be5e723bca fix 2026-01-12 17:29:44 +07:00
27ff57548f fix 2026-01-12 17:29:32 +07:00
d55ee98191 Merge remote-tracking branch 'origin/Submain' into Submain
# Conflicts:
#	app/src/main/java/com/example/ppb_kelompok2/MainActivity.kt
2026-01-12 17:29:10 +07:00
8c765fc7e2 fix 2026-01-12 17:28:56 +07:00
85345c4052 fix 2026-01-12 17:25:22 +07:00
8253b4adeb fix 2026-01-12 17:15:00 +07:00
23ff80ec12 fix 2026-01-12 16:43:42 +07:00
HadiPrakosou-HD
63d65acc35 Perubahan UI UX 2026-01-12 16:41:31 +07:00
HadiPrakosou-HD
e290b3c28a Merge remote-tracking branch 'HadiPsikologi/Submain' into Submain
# Conflicts:
#	app/src/main/java/com/example/ppb_kelompok2/MainActivity.kt
2026-01-12 16:41:12 +07:00
HadiPrakosou-HD
78ec7c1a89 Perubahan UI UX 2026-01-12 16:40:11 +07:00
HadiPrakosou-HD
ff5dcd893e Perubahan UI UX 2026-01-12 16:39:22 +07:00
214af2312f Perbaikan UI/UX 2026-01-12 16:11:41 +07:00
2365e0b907 Perbaikan UI/UX 2026-01-10 00:05:29 +07:00
HadiPrakosou-HD
6602e0e143 fixing Oauth 2026-01-09 22:59:13 +07:00
HadiPrakosou-HD
5ae0b78497 Merge remote-tracking branch 'HadiPsikologi/Submain' into Submain
# Conflicts:
#	app/build.gradle.kts
#	app/src/main/java/com/example/ppb_kelompok2/MainActivity.kt
2026-01-05 21:02:12 +07:00
HadiPrakosou-HD
b7315ea5c0 fixing 2026-01-05 21:01:18 +07:00
7046948c70 update 2026-01-02 23:37:01 +07:00
RyanMaulana23
d0b773b6ef fixing 2026-01-02 22:28:31 +07:00
RyanMaulana23
6d21baa3f3 fixing 2026-01-02 22:15:11 +07:00
RyanMaulana23
a83e671ece fixxing 2026-01-02 22:12:06 +07:00
RyanMaulana23
7fe8f9a0df Oauth, Model ML, Firebase 2025-12-22 17:30:31 +07:00
18 changed files with 723 additions and 759 deletions

1
.idea/.name generated Normal file
View File

@ -0,0 +1 @@
PPB_Kelompok2

123
.idea/codeStyles/Project.xml generated Normal file
View File

@ -0,0 +1,123 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<JetCodeStyleSettings>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</codeStyleSettings>
</code_scheme>
</component>

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View File

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

6
.idea/studiobot.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="StudioBotProjectSettings">
<option name="shareContext" value="OptedIn" />
</component>
</project>

View File

@ -1,23 +1,36 @@
import java.util.Properties
import java.io.FileInputStream
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.google.services)
}
// Load properties from local.properties file
val localProperties = Properties()
val localPropertiesFile = rootProject.file("local.properties")
if (localPropertiesFile.exists()) {
localProperties.load(FileInputStream(localPropertiesFile))
}
android {
namespace = "com.example.ppb_kelompok2"
compileSdk {
version = release(36)
}
compileSdk = 35
defaultConfig {
applicationId = "com.example.ppb_kelompok2"
minSdk = 25
targetSdk = 36
targetSdk = 35
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
// Expose the API key as a BuildConfig field
// This reads the HF_API_KEY from your local.properties file
buildConfigField("String", "HF_API_KEY", "\"${localProperties.getProperty("HF_API_KEY") ?: ""}\"")
}
buildTypes {
@ -38,6 +51,7 @@ android {
}
buildFeatures {
compose = true
buildConfig = true // Ensure this is enabled
}
}
@ -52,6 +66,15 @@ dependencies {
implementation(libs.androidx.compose.material3)
implementation("androidx.compose.material:material-icons-extended")
implementation("androidx.navigation:navigation-compose:2.9.6")
implementation(platform(libs.firebase.bom))
implementation(libs.firebase.auth.ktx)
implementation(libs.firebase.firestore.ktx)
implementation(libs.play.services.auth)
implementation(libs.retrofit)
implementation(libs.retrofit.gson)
implementation(libs.okhttp.logging)
implementation(libs.coil.compose)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)

29
app/google-services.json Normal file
View File

@ -0,0 +1,29 @@
{
"project_info": {
"project_number": "532164852718",
"project_id": "jurnal-psikologi",
"storage_bucket": "jurnal-psikologi.firebasestorage.app"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:532164852718:android:efd8ddbb729d947eaeecff",
"android_client_info": {
"package_name": "com.example.ppb_kelompok2"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyBnq_cjey_sz1KfJQ1mCJlvK61lWEQATis"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
}
],
"configuration_version": "1"
}

View File

@ -2,13 +2,20 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- Izin Internet (WAJIB untuk Firebase & API) -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:icon="@mipmap/ic_launcher_mindtrack"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:roundIcon="@mipmap/ic_launcher_mindtrack_round"
android:supportsRtl="true"
android:theme="@style/Theme.PPB_Kelompok2">
<activity
@ -22,6 +29,8 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".ReminderReceiver" android:enabled="true" android:exported="false"/>
</application>
</manifest>

View File

@ -0,0 +1,79 @@
package com.example.ppb_kelompok2
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.Body
import retrofit2.http.Header
import retrofit2.http.POST
// --- 1. Sentiment Analysis Models ---
data class SentimentRequest(val inputs: String)
typealias SentimentResponse = List<List<EmotionScore>>
data class EmotionScore(
val label: String,
val score: Float
)
// --- 2. Zero-Shot Classification Models ---
data class ZeroShotRequest(
val inputs: String,
val parameters: ZeroShotParameters
)
data class ZeroShotParameters(
val candidate_labels: List<String>,
val multi_label: Boolean = true // True = satu teks bisa masuk ke banyak kategori
)
data class ZeroShotResponse(
val sequence: String,
val labels: List<String>,
val scores: List<Float>
)
// --- 3. Interface API Definition ---
interface HuggingFaceApiService {
// Model 1: Emosi (Inggris) - Cepat & Ringan
@POST("models/j-hartmann/emotion-english-distilroberta-base")
suspend fun analyzeEmotion(
@Header("Authorization") authHeader: String,
@Body request: SentimentRequest
): SentimentResponse
// Model 2: Zero-Shot Classification (Multilingual) - Lebih Berat tapi Detail
// Menggunakan joeddav/xlm-roberta-large-xnli untuk support Bahasa Indonesia
@POST("models/joeddav/xlm-roberta-large-xnli")
suspend fun analyzeZeroShot(
@Header("Authorization") authHeader: String,
@Body request: ZeroShotRequest
): ZeroShotResponse
}
// --- 4. Singleton Instance (with Logging) ---
object RetrofitClient {
private const val BASE_URL = "https://api-inference.huggingface.co/"
// Membuat Interceptor untuk logging. Level BODY akan menampilkan semua detail request/response.
private val loggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
// Menambahkan interceptor ke OkHttpClient
private val httpClient = OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.build()
val apiService: HuggingFaceApiService by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.client(httpClient) // Menggunakan client custom yang sudah ada logger-nya
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(HuggingFaceApiService::class.java)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,62 @@
package com.example.ppb_kelompok2
import android.Manifest
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
class ReminderReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val title = intent.getStringExtra("title") ?: "MindTrack Reminder"
val message = intent.getStringExtra("message") ?: "Waktunya untuk check-in kesehatan mental Anda!"
showNotification(context, title, message)
}
private fun showNotification(context: Context, title: String, message: String) {
val channelId = "mindtrack_reminders"
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val name = "MindTrack Reminders"
val descriptionText = "Daily reminders for journaling and tests"
val importance = NotificationManager.IMPORTANCE_DEFAULT
val channel = NotificationChannel(channelId, name, importance).apply {
description = descriptionText
}
val notificationManager: NotificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
val intent = Intent(context, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
val builder = NotificationCompat.Builder(context, channelId)
.setSmallIcon(android.R.drawable.ic_dialog_info) // Ganti dengan icon aplikasi Anda jika ada
.setContentTitle(title)
.setContentText(message)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
with(NotificationManagerCompat.from(context)) {
if (ActivityCompat.checkSelfPermission(
context,
Manifest.permission.POST_NOTIFICATIONS
) == PackageManager.PERMISSION_GRANTED
) {
notify(1001, builder.build())
}
}
}
}

View File

@ -2,10 +2,17 @@ package com.example.ppb_kelompok2.ui.theme
import androidx.compose.ui.graphics.Color
// Pink Muda, Merah, dan Putih Theme
val PinkMuda = Color(0xFFFFD1DC) // Pink sangat muda
val MerahUtama = Color(0xFFFF5252) // Merah cerah
val MerahTua = Color(0xFFD32F2F) // Merah gelap untuk teks/aksen
val PutihMurni = Color(0xFFFFFFFF) // Putih
val PinkAksen = Color(0xFFFFB6C1) // Pink untuk variasi
// Tetap pertahankan default jika diperlukan (opsional)
val Purple80 = Color(0xFFD0BCFF)
val PurpleGrey80 = Color(0xFFCCC2DC)
val Pink80 = Color(0xFFEFB8C8)
val Purple40 = Color(0xFF6650a4)
val PurpleGrey40 = Color(0xFF625b71)
val Pink40 = Color(0xFF7D5260)

View File

@ -9,35 +9,36 @@ import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
private val DarkColorScheme = darkColorScheme(
primary = Purple80,
secondary = PurpleGrey80,
tertiary = Pink80
primary = MerahUtama,
secondary = PinkAksen,
tertiary = PinkMuda,
background = Color(0xFF1C1B1F),
surface = Color(0xFF1C1B1F),
onPrimary = Color.White,
onSecondary = Color.White,
onTertiary = Color.Black
)
private val LightColorScheme = lightColorScheme(
primary = Purple40,
secondary = PurpleGrey40,
tertiary = Pink40
/* Other default colors to override
background = Color(0xFFFFFBFE),
surface = Color(0xFFFFFBFE),
onPrimary = Color.White,
onSecondary = Color.White,
onTertiary = Color.White,
onBackground = Color(0xFF1C1B1F),
onSurface = Color(0xFF1C1B1F),
*/
primary = MerahUtama,
secondary = MerahTua,
tertiary = PinkMuda,
background = PutihMurni,
surface = PutihMurni,
onPrimary = PutihMurni,
onSecondary = PutihMurni,
onTertiary = Color.Black,
surfaceVariant = PinkMuda
)
@Composable
fun PPB_Kelompok2Theme(
darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is available on Android 12+
dynamicColor: Boolean = true,
dynamicColor: Boolean = false,
content: @Composable () -> Unit
) {
val colorScheme = when {
@ -45,7 +46,6 @@ fun PPB_Kelompok2Theme(
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}
darkTheme -> DarkColorScheme
else -> LightColorScheme
}

View File

@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="24"
android:viewportHeight="24">
<!-- Mental Health / Brain Icon Path -->
<path
android:fillColor="#FFFFFF"
android:pathData="M12,2C8.13,2 5,5.13 5,9c0,2.38 1.19,4.47 3,5.74V17c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-2.26c1.81,-1.27 3,-3.36 3,-5.74 0,-3.87 -3.13,-7 -7,-7zM14.5,13.88l-0.85,0.6V16h-3.3v-1.52l-0.85,-0.6C8.28,13.01 7.5,11.59 7.5,10.02c0,-2.48 2.02,-4.5 4.5,-4.5s4.5,2.02 4.5,4.5c0,1.57 -0.78,2.99 -2,3.86z"/>
<!-- Spark/Idea accents -->
<path
android:fillColor="#FFD700"
android:pathData="M12,6c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1z"/>
</vector>

View File

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

View File

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

View File

@ -7,4 +7,7 @@
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<!-- MindTrack Brand Colors -->
<color name="mindtrack_primary">#4A90E2</color> <!-- Calming Blue -->
</resources>

View File

@ -3,4 +3,5 @@ plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.kotlin.compose) apply false
alias(libs.plugins.google.services) apply false
}

View File

@ -1,5 +1,5 @@
[versions]
agp = "8.13.1"
agp = "8.13.2"
kotlin = "2.0.21"
coreKtx = "1.10.1"
junit = "4.13.2"
@ -8,6 +8,12 @@ espressoCore = "3.5.1"
lifecycleRuntimeKtx = "2.6.1"
activityCompose = "1.8.0"
composeBom = "2024.09.00"
googleServices = "4.4.2"
firebaseBom = "33.1.2"
playServicesAuth = "20.7.0"
retrofit = "2.9.0"
okhttp = "4.12.0"
coil = "2.5.0"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@ -24,9 +30,17 @@ androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "u
androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" }
firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "firebaseBom" }
firebase-auth-ktx = { group = "com.google.firebase", name = "firebase-auth-ktx" }
firebase-firestore-ktx = { group = "com.google.firebase", name = "firebase-firestore-ktx" }
play-services-auth = { group = "com.google.android.gms", name = "play-services-auth", version.ref = "playServicesAuth" }
retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
retrofit-gson = { group = "com.squareup.retrofit2", name = "converter-gson", version.ref = "retrofit" }
okhttp-logging = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp" }
coil-compose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coil" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
google-services = { id = "com.google.gms.google-services", version.ref = "googleServices" }