commit bc63ed83bb8ea19876fe435acf3201bd9be19cfd Author: HagaDalpintoGinting Date: Tue Dec 16 22:40:40 2025 +0700 first push diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/.gitignore @@ -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 diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..ce7b4fd --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Step&Drink \ No newline at end of file diff --git a/.idea/AndroidProjectSystem.xml b/.idea/AndroidProjectSystem.xml new file mode 100644 index 0000000..4a53bee --- /dev/null +++ b/.idea/AndroidProjectSystem.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b86273d --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..b268ef3 --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..639c779 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..7061a0d --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,61 @@ + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..b2c751a --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..16660f1 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..687caca --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,90 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) + alias(libs.plugins.ksp) +} + +android { + namespace = "com.example.stepdrink" + compileSdk { + version = release(36) + } + + defaultConfig { + applicationId = "com.example.stepdrink" + minSdk = 24 + targetSdk = 36 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = "11" + } + buildFeatures { + compose = true + } +} + +dependencies { + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.compose.ui) + implementation(libs.androidx.compose.ui.graphics) + implementation(libs.androidx.compose.ui.tooling.preview) + implementation(libs.androidx.compose.material3) + // Core Android + implementation("androidx.core:core-ktx:1.12.0") + implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0") + implementation("androidx.activity:activity-compose:1.8.2") + + // Compose + implementation(platform("androidx.compose:compose-bom:2024.02.00")) + implementation("androidx.compose.ui:ui") + implementation("androidx.compose.ui:ui-graphics") + implementation("androidx.compose.ui:ui-tooling-preview") + implementation("androidx.compose.material3:material3") + implementation("androidx.compose.material:material-icons-extended") + + // Navigation Compose + implementation("androidx.navigation:navigation-compose:2.7.7") + + // Room Database + implementation("androidx.room:room-runtime:2.6.1") + implementation("androidx.room:room-ktx:2.6.1") + ksp("androidx.room:room-compiler:2.6.1") + + // ViewModel Compose + implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0") + + // Coroutines + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3") + + // DataStore (untuk preferences) + implementation("androidx.datastore:datastore-preferences:1.0.0") + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.compose.ui.test.junit4) + debugImplementation(libs.androidx.compose.ui.tooling) + debugImplementation(libs.androidx.compose.ui.test.manifest) +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -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 \ No newline at end of file diff --git a/app/src/androidTest/java/com/example/stepdrink/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/example/stepdrink/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..63d77db --- /dev/null +++ b/app/src/androidTest/java/com/example/stepdrink/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.example.stepdrink + +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.stepdrink", appContext.packageName) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..ef7126a --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/example/stepdrink/MainActivity.kt b/app/src/main/java/com/example/stepdrink/MainActivity.kt new file mode 100644 index 0000000..c361896 --- /dev/null +++ b/app/src/main/java/com/example/stepdrink/MainActivity.kt @@ -0,0 +1,41 @@ +package com.example.stepdrink + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.ui.Modifier +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.compose.rememberNavController +import com.example.stepdrink.ui.navigation.NavGraph +import com.example.stepdrink.ui.theme.StepDrinkTheme +import com.example.stepdrink.viewmodel.StepViewModel +import com.example.stepdrink.viewmodel.WaterViewModel + +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + setContent { + StepDrinkTheme { + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background + ) { + val navController = rememberNavController() + val stepViewModel: StepViewModel = viewModel() + val waterViewModel: WaterViewModel = viewModel() + + NavGraph( + navController = navController, + stepViewModel = stepViewModel, + waterViewModel = waterViewModel + ) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/data/local/dao/StepDao.kt b/app/src/main/java/data/local/dao/StepDao.kt new file mode 100644 index 0000000..90b3afe --- /dev/null +++ b/app/src/main/java/data/local/dao/StepDao.kt @@ -0,0 +1,23 @@ +package com.example.stepdrink.data.local.dao + +import androidx.room.* +import kotlinx.coroutines.flow.Flow +import com.example.stepdrink.data.local.entity.StepRecord + +@Dao +interface StepDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertStepRecord(stepRecord: StepRecord) + + @Query("SELECT * FROM step_records WHERE date = :date") + fun getStepsByDate(date: String): Flow + + @Query("SELECT * FROM step_records ORDER BY date DESC LIMIT 7") + fun getLast7DaysSteps(): Flow> + + @Query("SELECT * FROM step_records ORDER BY date DESC") + fun getAllSteps(): Flow> + + @Update + suspend fun updateStepRecord(stepRecord: StepRecord) +} \ No newline at end of file diff --git a/app/src/main/java/data/local/dao/WaterDao.kt b/app/src/main/java/data/local/dao/WaterDao.kt new file mode 100644 index 0000000..c85cf9e --- /dev/null +++ b/app/src/main/java/data/local/dao/WaterDao.kt @@ -0,0 +1,23 @@ +package com.example.stepdrink.data.local.dao + +import androidx.room.* +import com.example.stepdrink.data.local.entity.WaterRecord +import kotlinx.coroutines.flow.Flow + +@Dao +interface WaterDao { + @Insert + suspend fun insertWaterRecord(waterRecord: WaterRecord) + + @Query("SELECT * FROM water_records WHERE date = :date ORDER BY timestamp DESC") + fun getWaterRecordsByDate(date: String): Flow> + + @Query("SELECT SUM(amount) FROM water_records WHERE date = :date") + fun getTotalWaterByDate(date: String): Flow + + @Query("SELECT * FROM water_records ORDER BY date DESC LIMIT 7") + fun getLast7DaysWater(): Flow> + + @Delete + suspend fun deleteWaterRecord(waterRecord: WaterRecord) +} \ No newline at end of file diff --git a/app/src/main/java/data/local/database/AppDatabase.kt b/app/src/main/java/data/local/database/AppDatabase.kt new file mode 100644 index 0000000..e27ca8d --- /dev/null +++ b/app/src/main/java/data/local/database/AppDatabase.kt @@ -0,0 +1,37 @@ +package com.example.stepdrink.data.local.database + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase +import com.example.stepdrink.data.local.dao.StepDao +import com.example.stepdrink.data.local.dao.WaterDao +import com.example.stepdrink.data.local.entity.StepRecord +import com.example.stepdrink.data.local.entity.WaterRecord + +@Database( + entities = [StepRecord::class, WaterRecord::class], + version = 1, + exportSchema = false +) +abstract class AppDatabase : RoomDatabase() { + abstract fun stepDao(): StepDao + abstract fun waterDao(): WaterDao + + companion object { + @Volatile + private var INSTANCE: AppDatabase? = null + + fun getDatabase(context: Context): AppDatabase { + return INSTANCE ?: synchronized(this) { + val instance = Room.databaseBuilder( + context.applicationContext, + AppDatabase::class.java, + "step_drink_database" + ).build() + INSTANCE = instance + instance + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/data/local/entitiy/StepRecord.kt b/app/src/main/java/data/local/entitiy/StepRecord.kt new file mode 100644 index 0000000..b01e94a --- /dev/null +++ b/app/src/main/java/data/local/entitiy/StepRecord.kt @@ -0,0 +1,14 @@ +package com.example.stepdrink.data.local.entity + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "step_records") +data class StepRecord( + @PrimaryKey(autoGenerate = true) + val id: Int = 0, + val date: String, // Format: "yyyy-MM-dd" + val steps: Int, + val timestamp: Long = System.currentTimeMillis() +) + diff --git a/app/src/main/java/data/local/entitiy/WaterRecord.kt b/app/src/main/java/data/local/entitiy/WaterRecord.kt new file mode 100644 index 0000000..fb276a5 --- /dev/null +++ b/app/src/main/java/data/local/entitiy/WaterRecord.kt @@ -0,0 +1,14 @@ +package com.example.stepdrink.data.local.entity + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "water_records") +data class WaterRecord( + @PrimaryKey(autoGenerate = true) + val id: Int = 0, + val date: String, // Format: "yyyy-MM-dd" + val amount: Int, // dalam ml + val timestamp: Long = System.currentTimeMillis() +) + diff --git a/app/src/main/java/data/repository/StepRepository.kt b/app/src/main/java/data/repository/StepRepository.kt new file mode 100644 index 0000000..fdfce6c --- /dev/null +++ b/app/src/main/java/data/repository/StepRepository.kt @@ -0,0 +1,24 @@ +package com.example.stepdrink.data.repository + +import com.example.stepdrink.data.local.dao.StepDao +import com.example.stepdrink.data.local.entity.StepRecord +import kotlinx.coroutines.flow.Flow + +class StepRepository(private val stepDao: StepDao) { + + fun getStepsByDate(date: String): Flow { + return stepDao.getStepsByDate(date) + } + + fun getLast7DaysSteps(): Flow> { + return stepDao.getLast7DaysSteps() + } + + suspend fun insertOrUpdateSteps(date: String, steps: Int) { + stepDao.insertStepRecord(StepRecord(date = date, steps = steps)) + } + + suspend fun updateStepRecord(stepRecord: StepRecord) { + stepDao.updateStepRecord(stepRecord) + } +} \ No newline at end of file diff --git a/app/src/main/java/data/repository/WaterRepository.kt b/app/src/main/java/data/repository/WaterRepository.kt new file mode 100644 index 0000000..9dd2cc5 --- /dev/null +++ b/app/src/main/java/data/repository/WaterRepository.kt @@ -0,0 +1,28 @@ +package com.example.stepdrink.data.repository + +import com.example.stepdrink.data.local.dao.WaterDao +import com.example.stepdrink.data.local.entity.WaterRecord +import kotlinx.coroutines.flow.Flow + +class WaterRepository(private val waterDao: WaterDao) { + + fun getWaterRecordsByDate(date: String): Flow> { + return waterDao.getWaterRecordsByDate(date) + } + + fun getTotalWaterByDate(date: String): Flow { + return waterDao.getTotalWaterByDate(date) + } + + fun getLast7DaysWater(): Flow> { + return waterDao.getLast7DaysWater() + } + + suspend fun addWaterRecord(date: String, amount: Int) { + waterDao.insertWaterRecord(WaterRecord(date = date, amount = amount)) + } + + suspend fun deleteWaterRecord(waterRecord: WaterRecord) { + waterDao.deleteWaterRecord(waterRecord) + } +} \ No newline at end of file diff --git a/app/src/main/java/sensor/StepCounterManager.kt b/app/src/main/java/sensor/StepCounterManager.kt new file mode 100644 index 0000000..c6e8fea --- /dev/null +++ b/app/src/main/java/sensor/StepCounterManager.kt @@ -0,0 +1,59 @@ +package com.example.stepdrink.sensor + +import android.content.Context +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow + +class StepCounterManager(context: Context) : SensorEventListener { + + private val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager + private val stepCounterSensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER) + + private val _totalSteps = MutableStateFlow(0) + val totalSteps: StateFlow = _totalSteps.asStateFlow() + + private var initialSteps = -1 + private var sessionStartSteps = 0 + + fun isSensorAvailable(): Boolean = stepCounterSensor != null + + fun startTracking() { + stepCounterSensor?.let { + sensorManager.registerListener(this, it, SensorManager.SENSOR_DELAY_UI) + } + } + + fun stopTracking() { + sensorManager.unregisterListener(this) + } + + fun resetSteps() { + initialSteps = -1 + sessionStartSteps = 0 + _totalSteps.value = 0 + } + + override fun onSensorChanged(event: SensorEvent?) { + event?.let { + if (it.sensor.type == Sensor.TYPE_STEP_COUNTER) { + val currentSteps = it.values[0].toInt() + + if (initialSteps == -1) { + initialSteps = currentSteps + sessionStartSteps = currentSteps + } + + _totalSteps.value = currentSteps - sessionStartSteps + } + } + } + + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { + // Not needed + } +} \ No newline at end of file diff --git a/app/src/main/java/ui/components/StatCard.kt b/app/src/main/java/ui/components/StatCard.kt new file mode 100644 index 0000000..1722ac2 --- /dev/null +++ b/app/src/main/java/ui/components/StatCard.kt @@ -0,0 +1,78 @@ +package com.example.stepdrink.ui.components + +import androidx.compose.foundation.layout.* +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp + +@Composable +fun StatCard( + icon: ImageVector, + title: String, + value: String, + subtitle: String, + progress: Float, + onClick: () -> Unit, + modifier: Modifier = Modifier +) { + Card( + onClick = onClick, + modifier = modifier.fillMaxWidth(), + elevation = CardDefaults.cardElevation(defaultElevation = 2.dp) + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp) + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = icon, + contentDescription = title, + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(32.dp) + ) + + Column( + horizontalAlignment = Alignment.End + ) { + Text( + text = value, + style = MaterialTheme.typography.headlineMedium, + fontWeight = FontWeight.Bold + ) + Text( + text = title, + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + + Spacer(modifier = Modifier.height(12.dp)) + + LinearProgressIndicator( + progress = { progress }, + modifier = Modifier + .fillMaxWidth() + .height(8.dp), + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = subtitle, + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ui/navigation/NavGraph.kt b/app/src/main/java/ui/navigation/NavGraph.kt new file mode 100644 index 0000000..4afc0d2 --- /dev/null +++ b/app/src/main/java/ui/navigation/NavGraph.kt @@ -0,0 +1,45 @@ +package com.example.stepdrink.ui.navigation + +import androidx.compose.runtime.Composable +import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import com.example.stepdrink.ui.screen.home.HomeScreen +import com.example.stepdrink.ui.screen.steps.StepsScreen +import com.example.stepdrink.ui.screen.water.WaterScreen +import com.example.stepdrink.viewmodel.StepViewModel +import com.example.stepdrink.viewmodel.WaterViewModel + +@Composable +fun NavGraph( + navController: NavHostController, + stepViewModel: StepViewModel, + waterViewModel: WaterViewModel +) { + NavHost( + navController = navController, + startDestination = Screen.Home.route + ) { + composable(Screen.Home.route) { + HomeScreen( + navController = navController, + stepViewModel = stepViewModel, + waterViewModel = waterViewModel + ) + } + + composable(Screen.Steps.route) { + StepsScreen( + navController = navController, + viewModel = stepViewModel + ) + } + + composable(Screen.Water.route) { + WaterScreen( + navController = navController, + viewModel = waterViewModel + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ui/navigation/Screen.kt b/app/src/main/java/ui/navigation/Screen.kt new file mode 100644 index 0000000..2ef4f3b --- /dev/null +++ b/app/src/main/java/ui/navigation/Screen.kt @@ -0,0 +1,7 @@ +package com.example.stepdrink.ui.navigation + +sealed class Screen(val route: String) { + object Home : Screen("home") + object Steps : Screen("steps") + object Water : Screen("water") +} \ No newline at end of file diff --git a/app/src/main/java/ui/screen/home/HomeScreen.kt b/app/src/main/java/ui/screen/home/HomeScreen.kt new file mode 100644 index 0000000..26b2668 --- /dev/null +++ b/app/src/main/java/ui/screen/home/HomeScreen.kt @@ -0,0 +1,105 @@ +package com.example.stepdrink.ui.screen.home + +import androidx.compose.foundation.layout.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.DirectionsWalk +import androidx.compose.material.icons.filled.WaterDrop +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.navigation.NavController +import com.example.stepdrink.ui.components.StatCard +import com.example.stepdrink.ui.navigation.Screen +import com.example.stepdrink.viewmodel.StepViewModel +import com.example.stepdrink.viewmodel.WaterViewModel + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun HomeScreen( + navController: NavController, + stepViewModel: StepViewModel, + waterViewModel: WaterViewModel +) { + val todaySteps by stepViewModel.todaySteps.collectAsState() + val stepGoal by stepViewModel.dailyGoal.collectAsState() + val todayWater by waterViewModel.todayTotalWater.collectAsState() + val waterGoal by waterViewModel.dailyGoal.collectAsState() + + Scaffold( + topBar = { + TopAppBar( + title = { + Text( + text = "Step & Drink", + fontWeight = FontWeight.Bold + ) + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.primaryContainer, + titleContentColor = MaterialTheme.colorScheme.onPrimaryContainer + ) + ) + } + ) { paddingValues -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues) + .padding(16.dp), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + Text( + text = "Aktivitas Hari Ini", + style = MaterialTheme.typography.headlineSmall, + fontWeight = FontWeight.Bold + ) + + // Steps Card + StatCard( + icon = Icons.Default.DirectionsWalk, + title = "Langkah", + value = "${todaySteps?.steps ?: 0}", + subtitle = "Target: $stepGoal langkah", + progress = (todaySteps?.steps ?: 0).toFloat() / stepGoal.toFloat(), + onClick = { navController.navigate(Screen.Steps.route) } + ) + + // Water Card + StatCard( + icon = Icons.Default.WaterDrop, + title = "Air Minum", + value = "${todayWater}ml", + subtitle = "Target: ${waterGoal}ml", + progress = todayWater.toFloat() / waterGoal.toFloat(), + onClick = { navController.navigate(Screen.Water.route) } + ) + + Spacer(modifier = Modifier.weight(1f)) + + // Tips Card + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.secondaryContainer + ) + ) { + Column( + modifier = Modifier.padding(16.dp) + ) { + Text( + text = "💡 Tips Kesehatan", + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.Bold + ) + Spacer(modifier = Modifier.height(8.dp)) + Text( + text = "Berjalan 10.000 langkah per hari dan minum 2 liter air dapat meningkatkan kesehatan tubuh!", + style = MaterialTheme.typography.bodyMedium + ) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ui/screen/steps/StepsScreen.kt b/app/src/main/java/ui/screen/steps/StepsScreen.kt new file mode 100644 index 0000000..52b2e1f --- /dev/null +++ b/app/src/main/java/ui/screen/steps/StepsScreen.kt @@ -0,0 +1,195 @@ +package com.example.stepdrink.ui.screen.steps + +import android.Manifest +import android.os.Build +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.DirectionsWalk +import androidx.compose.material.icons.filled.PlayArrow +import androidx.compose.material.icons.filled.Stop +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.navigation.NavController +import com.example.stepdrink.viewmodel.StepViewModel + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun StepsScreen( + navController: NavController, + viewModel: StepViewModel +) { + val todaySteps by viewModel.todaySteps.collectAsState() + val stepGoal by viewModel.dailyGoal.collectAsState() + val sensorSteps by viewModel.stepCounterManager.totalSteps.collectAsState() + val last7Days by viewModel.last7DaysSteps.collectAsState() + + var isTracking by remember { mutableStateOf(false) } + var permissionGranted by remember { mutableStateOf(false) } + + // Permission launcher untuk Android 10+ + val permissionLauncher = rememberLauncherForActivityResult( + ActivityResultContracts.RequestPermission() + ) { isGranted -> + permissionGranted = isGranted + if (isGranted) { + viewModel.stepCounterManager.startTracking() + isTracking = true + } + } + + Scaffold( + topBar = { + TopAppBar( + title = { Text("Pelacak Langkah") }, + navigationIcon = { + IconButton(onClick = { navController.popBackStack() }) { + Icon(Icons.Default.ArrowBack, "Kembali") + } + } + ) + }, + floatingActionButton = { + FloatingActionButton( + onClick = { + if (isTracking) { + viewModel.stepCounterManager.stopTracking() + isTracking = false + } else { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + permissionLauncher.launch(Manifest.permission.ACTIVITY_RECOGNITION) + } else { + viewModel.stepCounterManager.startTracking() + isTracking = true + } + } + } + ) { + Icon( + imageVector = if (isTracking) Icons.Default.Stop else Icons.Default.PlayArrow, + contentDescription = if (isTracking) "Stop" else "Start" + ) + } + } + ) { paddingValues -> + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues) + .padding(16.dp), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + item { + // Current Steps Card + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.primaryContainer + ) + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(24.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Icon( + imageVector = Icons.Default.DirectionsWalk, + contentDescription = null, + modifier = Modifier.size(64.dp), + tint = MaterialTheme.colorScheme.primary + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Text( + text = "${todaySteps?.steps ?: 0}", + style = MaterialTheme.typography.displayLarge, + fontWeight = FontWeight.Bold + ) + + Text( + text = "Langkah Hari Ini", + style = MaterialTheme.typography.titleMedium + ) + + Spacer(modifier = Modifier.height(16.dp)) + + LinearProgressIndicator( + progress = { + (todaySteps?.steps ?: 0).toFloat() / stepGoal.toFloat() + }, + modifier = Modifier + .fillMaxWidth() + .height(8.dp), + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = "Target: $stepGoal langkah", + style = MaterialTheme.typography.bodyMedium + ) + + if (isTracking) { + Spacer(modifier = Modifier.height(8.dp)) + Badge( + containerColor = MaterialTheme.colorScheme.tertiary + ) { + Text("Sedang Melacak: $sensorSteps langkah") + } + } + } + } + } + + item { + Text( + text = "Riwayat 7 Hari Terakhir", + style = MaterialTheme.typography.titleLarge, + fontWeight = FontWeight.Bold + ) + } + + items(last7Days) { record -> + Card( + modifier = Modifier.fillMaxWidth() + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Column { + Text( + text = record.date, + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.Bold + ) + Text( + text = "${record.steps} langkah", + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + + CircularProgressIndicator( + progress = { (record.steps.toFloat() / stepGoal.toFloat()).coerceIn(0f, 1f) }, + modifier = Modifier.size(48.dp), + ) + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ui/screen/water/WaterScreen.kt b/app/src/main/java/ui/screen/water/WaterScreen.kt new file mode 100644 index 0000000..8d31cb0 --- /dev/null +++ b/app/src/main/java/ui/screen/water/WaterScreen.kt @@ -0,0 +1,271 @@ +package com.example.stepdrink.ui.screen.water + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.* +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.navigation.NavController +import com.example.stepdrink.viewmodel.WaterViewModel +import java.text.SimpleDateFormat +import java.util.* + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun WaterScreen( + navController: NavController, + viewModel: WaterViewModel +) { + val todayRecords by viewModel.todayWaterRecords.collectAsState() + val totalWater by viewModel.todayTotalWater.collectAsState() + val waterGoal by viewModel.dailyGoal.collectAsState() + + var showDialog by remember { mutableStateOf(false) } + + Scaffold( + topBar = { + TopAppBar( + title = { Text("Pelacak Air Minum") }, + navigationIcon = { + IconButton(onClick = { navController.popBackStack() }) { + Icon(Icons.Default.ArrowBack, "Kembali") + } + } + ) + }, + floatingActionButton = { + FloatingActionButton( + onClick = { showDialog = true } + ) { + Icon(Icons.Default.Add, "Tambah") + } + } + ) { paddingValues -> + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues) + .padding(16.dp), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + item { + // Water Progress Card + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.tertiaryContainer + ) + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(24.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Icon( + imageVector = Icons.Default.WaterDrop, + contentDescription = null, + modifier = Modifier.size(64.dp), + tint = MaterialTheme.colorScheme.tertiary + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Text( + text = "${totalWater}ml", + style = MaterialTheme.typography.displayLarge, + fontWeight = FontWeight.Bold + ) + + Text( + text = "Air Minum Hari Ini", + style = MaterialTheme.typography.titleMedium + ) + + Spacer(modifier = Modifier.height(16.dp)) + + LinearProgressIndicator( + progress = { totalWater.toFloat() / waterGoal.toFloat() }, + modifier = Modifier + .fillMaxWidth() + .height(8.dp), + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = "Target: ${waterGoal}ml", + style = MaterialTheme.typography.bodyMedium + ) + } + } + } + + item { + // Quick Add Buttons + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + QuickAddButton( + amount = 250, + onClick = { viewModel.addWater(250) }, + modifier = Modifier.weight(1f) + ) + QuickAddButton( + amount = 500, + onClick = { viewModel.addWater(500) }, + modifier = Modifier.weight(1f) + ) + QuickAddButton( + amount = 1000, + onClick = { viewModel.addWater(1000) }, + modifier = Modifier.weight(1f) + ) + } + } + + item { + Text( + text = "Riwayat Hari Ini", + style = MaterialTheme.typography.titleLarge, + fontWeight = FontWeight.Bold + ) + } + + items(todayRecords) { record -> + WaterRecordItem( + amount = record.amount, + timestamp = record.timestamp, + onDelete = { viewModel.deleteWaterRecord(record) } + ) + } + } + } + + if (showDialog) { + AddWaterDialog( + onDismiss = { showDialog = false }, + onConfirm = { amount -> + viewModel.addWater(amount) + showDialog = false + } + ) + } +} + +@Composable +fun QuickAddButton( + amount: Int, + onClick: () -> Unit, + modifier: Modifier = Modifier +) { + OutlinedButton( + onClick = onClick, + modifier = modifier + ) { + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + Icon(Icons.Default.WaterDrop, contentDescription = null) + Text("${amount}ml") + } + } +} + +@Composable +fun WaterRecordItem( + amount: Int, + timestamp: Long, + onDelete: () -> Unit +) { + val timeFormat = remember { SimpleDateFormat("HH:mm", Locale.getDefault()) } + val time = timeFormat.format(Date(timestamp)) + + Card( + modifier = Modifier.fillMaxWidth() + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + Icon( + imageVector = Icons.Default.WaterDrop, + contentDescription = null, + tint = MaterialTheme.colorScheme.primary + ) + Column { + Text( + text = "${amount}ml", + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.Bold + ) + Text( + text = time, + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + + IconButton(onClick = onDelete) { + Icon( + imageVector = Icons.Default.Delete, + contentDescription = "Hapus", + tint = MaterialTheme.colorScheme.error + ) + } + } + } +} + +@Composable +fun AddWaterDialog( + onDismiss: () -> Unit, + onConfirm: (Int) -> Unit +) { + var amount by remember { mutableStateOf("") } + + AlertDialog( + onDismissRequest = onDismiss, + title = { Text("Tambah Air Minum") }, + text = { + OutlinedTextField( + value = amount, + onValueChange = { amount = it.filter { char -> char.isDigit() } }, + label = { Text("Jumlah (ml)") }, + singleLine = true + ) + }, + confirmButton = { + TextButton( + onClick = { + val amountInt = amount.toIntOrNull() + if (amountInt != null && amountInt > 0) { + onConfirm(amountInt) + } + } + ) { + Text("Tambah") + } + }, + dismissButton = { + TextButton(onClick = onDismiss) { + Text("Batal") + } + } + ) +} \ No newline at end of file diff --git a/app/src/main/java/ui/theme/theme.kt b/app/src/main/java/ui/theme/theme.kt new file mode 100644 index 0000000..86930df --- /dev/null +++ b/app/src/main/java/ui/theme/theme.kt @@ -0,0 +1,46 @@ +package com.example.stepdrink.ui.theme + +import android.app.Activity +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.platform.LocalView +import androidx.core.view.WindowCompat + +private val DarkColorScheme = darkColorScheme( + primary = androidx.compose.ui.graphics.Color(0xFF90CAF9), + secondary = androidx.compose.ui.graphics.Color(0xFF81C784), + tertiary = androidx.compose.ui.graphics.Color(0xFF64B5F6) +) + +private val LightColorScheme = lightColorScheme( + primary = androidx.compose.ui.graphics.Color(0xFF1976D2), + secondary = androidx.compose.ui.graphics.Color(0xFF388E3C), + tertiary = androidx.compose.ui.graphics.Color(0xFF0288D1) +) + +@Composable +fun StepDrinkTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + content: @Composable () -> Unit +) { + val colorScheme = if (darkTheme) DarkColorScheme else LightColorScheme + val view = LocalView.current + + if (!view.isInEditMode) { + SideEffect { + val window = (view.context as Activity).window + window.statusBarColor = colorScheme.primary.toArgb() + WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = !darkTheme + } + } + + MaterialTheme( + colorScheme = colorScheme, + content = content + ) +} \ No newline at end of file diff --git a/app/src/main/java/util/DateUtils.kt b/app/src/main/java/util/DateUtils.kt new file mode 100644 index 0000000..d58bde2 --- /dev/null +++ b/app/src/main/java/util/DateUtils.kt @@ -0,0 +1,22 @@ +package com.example.stepdrink.util + +import java.text.SimpleDateFormat +import java.util.* + +object DateUtils { + private val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) + + fun getCurrentDate(): String { + return dateFormat.format(Date()) + } + + fun formatDate(timestamp: Long): String { + return dateFormat.format(Date(timestamp)) + } + + fun getDateDaysAgo(daysAgo: Int): String { + val calendar = Calendar.getInstance() + calendar.add(Calendar.DAY_OF_YEAR, -daysAgo) + return dateFormat.format(calendar.time) + } +} \ No newline at end of file diff --git a/app/src/main/java/viewmodel/StepViewModel.kt b/app/src/main/java/viewmodel/StepViewModel.kt new file mode 100644 index 0000000..1fcca26 --- /dev/null +++ b/app/src/main/java/viewmodel/StepViewModel.kt @@ -0,0 +1,60 @@ +package com.example.stepdrink.viewmodel + +import android.app.Application +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.viewModelScope +import com.example.stepdrink.data.local.database.AppDatabase +import com.example.stepdrink.data.local.entity.StepRecord +import com.example.stepdrink.data.repository.StepRepository +import com.example.stepdrink.sensor.StepCounterManager +import com.example.stepdrink.util.DateUtils +import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch + +class StepViewModel(application: Application) : AndroidViewModel(application) { + + private val repository: StepRepository = StepRepository( + AppDatabase.getDatabase(application).stepDao() + ) + val stepCounterManager: StepCounterManager = StepCounterManager(application) + + private val _dailyGoal = MutableStateFlow(10000) + val dailyGoal: StateFlow = _dailyGoal.asStateFlow() + + val todaySteps: StateFlow = repository.getStepsByDate(DateUtils.getCurrentDate()) + .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), null) + + val last7DaysSteps: StateFlow> = repository.getLast7DaysSteps() + .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList()) + + init { + // Observe sensor dan update database + viewModelScope.launch { + stepCounterManager.totalSteps.collect { steps -> + if (steps > 0) { + updateTodaySteps(steps) + } + } + } + } + + private fun updateTodaySteps(steps: Int) { + viewModelScope.launch { + repository.insertOrUpdateSteps(DateUtils.getCurrentDate(), steps) + } + } + + fun setDailyGoal(goal: Int) { + _dailyGoal.value = goal + } + + fun getProgressPercentage(): Float { + val today = todaySteps.value?.steps ?: 0 + return (today.toFloat() / _dailyGoal.value.toFloat()).coerceIn(0f, 1f) + } + + override fun onCleared() { + super.onCleared() + stepCounterManager.stopTracking() + } +} \ No newline at end of file diff --git a/app/src/main/java/viewmodel/WaterViewModel.kt b/app/src/main/java/viewmodel/WaterViewModel.kt new file mode 100644 index 0000000..1e7261c --- /dev/null +++ b/app/src/main/java/viewmodel/WaterViewModel.kt @@ -0,0 +1,54 @@ +package com.example.stepdrink.viewmodel + +import android.app.Application +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.viewModelScope +import com.example.stepdrink.data.local.database.AppDatabase +import com.example.stepdrink.data.local.entity.WaterRecord +import com.example.stepdrink.data.repository.WaterRepository +import com.example.stepdrink.util.DateUtils +import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch + +class WaterViewModel(application: Application) : AndroidViewModel(application) { + + private val repository: WaterRepository = WaterRepository( + AppDatabase.getDatabase(application).waterDao() + ) + + private val _dailyGoal = MutableStateFlow(2000) // 2000ml = 2 liter + val dailyGoal: StateFlow = _dailyGoal.asStateFlow() + + val todayWaterRecords: StateFlow> = + repository.getWaterRecordsByDate(DateUtils.getCurrentDate()) + .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList()) + + val todayTotalWater: StateFlow = + repository.getTotalWaterByDate(DateUtils.getCurrentDate()) + .map { it ?: 0 } + .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), 0) + + val last7DaysWater: StateFlow> = + repository.getLast7DaysWater() + .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList()) + + fun addWater(amount: Int) { + viewModelScope.launch { + repository.addWaterRecord(DateUtils.getCurrentDate(), amount) + } + } + + fun deleteWaterRecord(record: WaterRecord) { + viewModelScope.launch { + repository.deleteWaterRecord(record) + } + } + + fun setDailyGoal(goal: Int) { + _dailyGoal.value = goal + } + + fun getProgressPercentage(): Float { + return (todayTotalWater.value.toFloat() / _dailyGoal.value.toFloat()).coerceIn(0f, 1f) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..f8c6127 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..10b2129 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + Step&Drink + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..dd02be5 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,5 @@ + + + +