diff --git a/.github/ISSUE_TEMPLATE/calculate-a-custom-tip-issue-template.md b/.github/ISSUE_TEMPLATE/calculate-a-custom-tip-issue-template.md new file mode 100644 index 0000000..61186a8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/calculate-a-custom-tip-issue-template.md @@ -0,0 +1,32 @@ +--- +name: Calculate a custom tip issue template +about: 'Issue template for Calculate a custom tip ' +title: 'Calculate a custom tip: Android Basics in Compose ' +labels: '' +assignees: '' + +--- + +**URL of codelab** + + +**In which task and step of the codelab can this issue be found?** + + +**Describe the problem** + + + + +**Steps to reproduce?** +1. Go to... +2. Click on... +3. See error... + +**Versions** +_Android Studio version:_ +_API version of the emulator:_ + + +**Additional information** +_Include screenshots if they would be useful in clarifying the problem._ diff --git a/.github/ISSUE_TEMPLATE/intro-to-state-issue-template.md b/.github/ISSUE_TEMPLATE/intro-to-state-issue-template.md new file mode 100644 index 0000000..2a148e9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/intro-to-state-issue-template.md @@ -0,0 +1,32 @@ +--- +name: Intro to state issue template +about: 'Issue template for Intro to state in Compose ' +title: 'Intro to state in Compose: Android Basics in Compose' +labels: '' +assignees: '' + +--- + +**URL of codelab** + + +**In which task and step of the codelab can this issue be found?** + + +**Describe the problem** + + + + +**Steps to reproduce?** +1. Go to... +2. Click on... +3. See error... + +**Versions** +_Android Studio version:_ +_API version of the emulator:_ + + +**Additional information** +_Include screenshots if they would be useful in clarifying the problem._ diff --git a/.github/renovate.json b/.github/renovate.json new file mode 100644 index 0000000..be8b65e --- /dev/null +++ b/.github/renovate.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "local>android/.github:renovate-config" + ], + "baseBranches": [ + "main", + "starter", + "state" + ] +} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..fdb5175 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,30 @@ +name: Build + +on: + pull_request: + branches: + - main + - starter + - state + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set Up JDK + uses: actions/setup-java@v4 + with: + distribution: 'zulu' # See 'Supported distributions' for available options + java-version: '17' + cache: 'gradle' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Setup Android SDK + uses: android-actions/setup-android@v3 + + - name: Build project and run local and device tests + run: ./gradlew :app:assembleDebug diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3a2358d --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +# built application files +*.apk +*.ap_ + +# Mac files +.DS_Store + +# files for the dex VM +*.dex + +# Java class files +*.class + +# generated files +bin/ +gen/ + +# Ignore gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ +proguard-project.txt + +# Eclipse files +.project +.classpath +.settings/ + +# Android Studio/IDEA +*.iml +.idea \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..3e0558e --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,36 @@ +# How to become a contributor and submit your own code + +## Contributor License Agreements + +We'd love to accept your sample apps and patches! Before we can take them, we +have to jump a couple of legal hurdles. + +Please fill out either the individual or corporate Contributor License Agreement +(CLA). + + * If you are an individual writing original source code and you're sure you + own the intellectual property, then you'll need to sign an [individual CLA] + (https://developers.google.com/open-source/cla/individual). + * If you work for a company that wants to allow you to contribute your work, + then you'll need to sign a [corporate CLA] + (https://developers.google.com/open-source/cla/corporate). + +Follow either of the two links above to access the appropriate CLA and +instructions for how to sign and return it. Once we receive it, we'll be able to +accept your pull requests. + +## Contributing A Patch + +1. Submit an issue describing your proposed change to the repo in question. +1. The repo owner will respond to your issue promptly. +1. If your proposed change is accepted, and you haven't already done so, sign a + Contributor License Agreement (see details above). +1. Fork the desired repo, develop and test your code changes. +1. Ensure that your code adheres to the existing style in the sample to which + you are contributing. Refer to the + [Google Cloud Platform Samples Style Guide] + (https://github.com/GoogleCloudPlatform/Template/wiki/style.html) for the + recommended coding standards for this organization. +1. Ensure that your code has an appropriate set of unit tests which all pass. +1. Submit a pull request. + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. 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..f786714 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +plugins { + id("com.android.application") + id("org.jetbrains.kotlin.android") + id("org.jetbrains.kotlin.plugin.compose") +} + +android { + compileSdk = 35 + + defaultConfig { + applicationId = "com.example.tiptime" + minSdk = 24 + targetSdk = 35 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + vectorDrawables { + useSupportLibrary = true + } + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = JavaVersion.VERSION_17.toString() + } + buildFeatures { + compose = true + } + packaging { + resources { + excludes += "/META-INF/{AL2.0,LGPL2.1}" + } + } + namespace = "com.example.tiptime" +} + +dependencies { + + implementation(platform("androidx.compose:compose-bom:2024.12.01")) + implementation("androidx.activity:activity-compose:1.9.3") + implementation("androidx.compose.material3:material3") + implementation("androidx.compose.ui:ui") + implementation("androidx.compose.ui:ui-tooling") + implementation("androidx.compose.ui:ui-tooling-preview") + implementation("androidx.core:core-ktx:1.15.0") + implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.7") + + testImplementation("junit:junit:4.13.2") + + androidTestImplementation(platform("androidx.compose:compose-bom:2024.12.01")) + androidTestImplementation("androidx.compose.ui:ui-test-junit4") + androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1") + androidTestImplementation("androidx.test.ext:junit:1.2.1") + + debugImplementation("androidx.compose.ui:ui-test-manifest") +} 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/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..e897dec --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png new file mode 100644 index 0000000..6c6b398 Binary files /dev/null and b/app/src/main/ic_launcher-playstore.png differ diff --git a/app/src/main/java/com/example/tiptime/MainActivity.kt b/app/src/main/java/com/example/tiptime/MainActivity.kt new file mode 100644 index 0000000..66caadc --- /dev/null +++ b/app/src/main/java/com/example/tiptime/MainActivity.kt @@ -0,0 +1,247 @@ +// Dirson Ali Wardana +// 202310715XXX +package com.example.tiptime + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + enableEdgeToEdge() + super.onCreate(savedInstanceState) + setContent { + Surface(modifier = Modifier.fillMaxSize()) { + BMIApp() + } + } + } +} + +@Composable +fun BMIApp() { + var started by remember { mutableStateOf(false) } + + if (!started) { + GetStartedScreen(onStart = { started = true }) + } else { + BMICalculatorScreen() + } +} + +@Composable +fun GetStartedScreen(onStart: () -> Unit) { + Box( + modifier = Modifier + .fillMaxSize() + .background( + Brush.verticalGradient( + listOf(Color(0xFFDDEEC7), Color(0xFFB6D7A8)) + ) + ), + contentAlignment = Alignment.Center + ) { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + + // 🏞️ Logo / ilustrasi Ghibli style + Image( + painter = painterResource(id = R.drawable.bmilogo), + contentDescription = "App Logo", + modifier = Modifier + .size(160.dp) + .padding(bottom = 24.dp) + ) + + Text( + text = "BMI CALCULATOR", + fontSize = 22.sp, + color = Color(0xFF375E3B), + textAlign = TextAlign.Center + ) + + Spacer(modifier = Modifier.height(24.dp)) + + Button( + onClick = onStart, + colors = ButtonDefaults.buttonColors(containerColor = Color(0xFF9C7B4B)), + shape = RoundedCornerShape(16.dp), + modifier = Modifier + .fillMaxWidth(0.6f) + .height(50.dp) + ) { + Text("Mulai Sekarang", color = Color.White, fontSize = 18.sp) + } + } + } +} + +@Composable +fun BMICalculatorScreen() { + var height by remember { mutableStateOf("") } + var weight by remember { mutableStateOf("") } + var useMetric by remember { mutableStateOf(true) } + + val heightVal = height.toDoubleOrNull() ?: 0.0 + val weightVal = weight.toDoubleOrNull() ?: 0.0 + val bmiVal = calculateBMIValue(heightVal, weightVal, useMetric) + val bmiText = String.format("%.2f", bmiVal) + val category = calculateBMICategory(bmiVal) + val imageRes = getCategoryImage(category) + + Box( + modifier = Modifier + .fillMaxSize() + .background( + Brush.verticalGradient( + listOf(Color(0xFFEAF4D3), Color(0xFFD2E3B8)) + ) + ) + ) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(24.dp) + .verticalScroll(rememberScrollState()), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = "Kalkulator BMI", + style = MaterialTheme.typography.headlineLarge, + color = Color(0xFF375E3B), + modifier = Modifier.padding(bottom = 16.dp) + ) + + OutlinedTextField( + value = height, + onValueChange = { height = it }, + label = { Text("Tinggi Badan (${if (useMetric) "cm" else "inch"})") }, + keyboardOptions = androidx.compose.foundation.text.KeyboardOptions( + keyboardType = KeyboardType.Number, + imeAction = ImeAction.Next + ), + modifier = Modifier.fillMaxWidth(), + colors = OutlinedTextFieldDefaults.colors( + focusedBorderColor = Color(0xFF375E3B), + focusedLabelColor = Color(0xFF375E3B) + ) + ) + + Spacer(modifier = Modifier.height(12.dp)) + + OutlinedTextField( + value = weight, + onValueChange = { weight = it }, + label = { Text("Berat Badan (${if (useMetric) "kg" else "lb"})") }, + keyboardOptions = androidx.compose.foundation.text.KeyboardOptions( + keyboardType = KeyboardType.Number, + imeAction = ImeAction.Done + ), + modifier = Modifier.fillMaxWidth(), + colors = OutlinedTextFieldDefaults.colors( + focusedBorderColor = Color(0xFF375E3B), + focusedLabelColor = Color(0xFF375E3B) + ) + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Button( + onClick = { useMetric = !useMetric }, + colors = ButtonDefaults.buttonColors(containerColor = Color(0xFF9C7B4B)), + shape = RoundedCornerShape(12.dp) + ) { + Text(if (useMetric) "Gunakan US (USC)" else "Gunakan Metric (SI)", color = Color.White) + } + + Spacer(modifier = Modifier.height(24.dp)) + + Card( + colors = CardDefaults.cardColors(containerColor = Color(0xFFFDF6E3)), + shape = RoundedCornerShape(20.dp), + modifier = Modifier.fillMaxWidth() + ) { + Column( + modifier = Modifier.padding(24.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = "BMI Anda: $bmiText", + style = MaterialTheme.typography.headlineMedium, + color = Color(0xFF375E3B) + ) + Text( + text = "Kategori: $category", + style = MaterialTheme.typography.titleMedium, + color = Color(0xFF8B4513) + ) + + if (imageRes != null) { + Spacer(modifier = Modifier.height(16.dp)) + Image( + painter = painterResource(id = imageRes), + contentDescription = category, + modifier = Modifier + .fillMaxWidth() + .height(220.dp) + ) + } + } + } + + Spacer(modifier = Modifier.height(32.dp)) + + Text( + text = "Dibuat oleh Dirson Ali Wardana\nUniversitas Bhayangkara Jakarta Raya\n© 2025", + style = MaterialTheme.typography.bodyMedium, + textAlign = TextAlign.Center, + color = Color(0xFF375E3B) + ) + } + } +} + +private fun calculateBMIValue(height: Double, weight: Double, useMetric: Boolean): Double { + if (height <= 0.0 || weight <= 0.0) return 0.0 + val heightInMeters = if (useMetric) height / 100 else height * 0.0254 + val weightInKg = if (useMetric) weight else weight * 0.453592 + return weightInKg / (heightInMeters * heightInMeters) +} + +private fun calculateBMICategory(bmi: Double): String { + return when { + bmi == 0.0 -> "-" + bmi < 18.5 -> "Kurus" + bmi < 24.9 -> "Normal" + bmi < 29.9 -> "Gemuk" + else -> "Obesitas" + } +} + +private fun getCategoryImage(category: String): Int? { + return when (category) { + "Kurus" -> R.drawable.kurusg + "Normal" -> R.drawable.normalg + "Gemuk" -> R.drawable.overweightg + "Obesitas" -> R.drawable.obesitasg + else -> null + } +} diff --git a/app/src/main/java/com/example/tiptime/ui/theme/Color.kt b/app/src/main/java/com/example/tiptime/ui/theme/Color.kt new file mode 100644 index 0000000..bc21042 --- /dev/null +++ b/app/src/main/java/com/example/tiptime/ui/theme/Color.kt @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.tiptime.ui.theme + +import androidx.compose.ui.graphics.Color + +val md_theme_light_primary = Color(0xFF984061) +val md_theme_light_onPrimary = Color(0xFFFFFFFF) +val md_theme_light_primaryContainer = Color(0xFFFFD9E2) +val md_theme_light_onPrimaryContainer = Color(0xFF3E001D) +val md_theme_light_secondary = Color(0xFF754B9C) +val md_theme_light_onSecondary = Color(0xFFFFFFFF) +val md_theme_light_secondaryContainer = Color(0xFFF1DBFF) +val md_theme_light_onSecondaryContainer = Color(0xFF2D0050) +val md_theme_light_tertiary = Color(0xFF984060) +val md_theme_light_onTertiary = Color(0xFFFFFFFF) +val md_theme_light_tertiaryContainer = Color(0xFFFFD9E2) +val md_theme_light_onTertiaryContainer = Color(0xFF3E001D) +val md_theme_light_error = Color(0xFFBA1A1A) +val md_theme_light_errorContainer = Color(0xFFFFDAD6) +val md_theme_light_onError = Color(0xFFFFFFFF) +val md_theme_light_onErrorContainer = Color(0xFF410002) +val md_theme_light_background = Color(0xFFFAFCFF) +val md_theme_light_onBackground = Color(0xFF001F2A) +val md_theme_light_surface = Color(0xFFFAFCFF) +val md_theme_light_onSurface = Color(0xFF001F2A) +val md_theme_light_surfaceVariant = Color(0xFFF2DDE2) +val md_theme_light_onSurfaceVariant = Color(0xFF514347) +val md_theme_light_outline = Color(0xFF837377) +val md_theme_light_inverseOnSurface = Color(0xFFE1F4FF) +val md_theme_light_inverseSurface = Color(0xFF003547) +val md_theme_light_inversePrimary = Color(0xFFFFB0C8) +val md_theme_light_surfaceTint = Color(0xFF984061) +val md_theme_light_outlineVariant = Color(0xFFD5C2C6) +val md_theme_light_scrim = Color(0xFF000000) + +val md_theme_dark_primary = Color(0xFFFFB0C8) +val md_theme_dark_onPrimary = Color(0xFF5E1133) +val md_theme_dark_primaryContainer = Color(0xFF7B2949) +val md_theme_dark_onPrimaryContainer = Color(0xFFFFD9E2) +val md_theme_dark_secondary = Color(0xFFDEB7FF) +val md_theme_dark_onSecondary = Color(0xFF44196A) +val md_theme_dark_secondaryContainer = Color(0xFF5C3382) +val md_theme_dark_onSecondaryContainer = Color(0xFFF1DBFF) +val md_theme_dark_tertiary = Color(0xFFFFB1C7) +val md_theme_dark_onTertiary = Color(0xFF5E1132) +val md_theme_dark_tertiaryContainer = Color(0xFF7B2948) +val md_theme_dark_onTertiaryContainer = Color(0xFFFFD9E2) +val md_theme_dark_error = Color(0xFFFFB4AB) +val md_theme_dark_errorContainer = Color(0xFF93000A) +val md_theme_dark_onError = Color(0xFF690005) +val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6) +val md_theme_dark_background = Color(0xFF001F2A) +val md_theme_dark_onBackground = Color(0xFFBFE9FF) +val md_theme_dark_surface = Color(0xFF001F2A) +val md_theme_dark_onSurface = Color(0xFFBFE9FF) +val md_theme_dark_surfaceVariant = Color(0xFF514347) +val md_theme_dark_onSurfaceVariant = Color(0xFFD5C2C6) +val md_theme_dark_outline = Color(0xFF9E8C90) +val md_theme_dark_inverseOnSurface = Color(0xFF001F2A) +val md_theme_dark_inverseSurface = Color(0xFFBFE9FF) +val md_theme_dark_inversePrimary = Color(0xFF984061) +val md_theme_dark_surfaceTint = Color(0xFFFFB0C8) +val md_theme_dark_outlineVariant = Color(0xFF514347) +val md_theme_dark_scrim = Color(0xFF000000) diff --git a/app/src/main/java/com/example/tiptime/ui/theme/Theme.kt b/app/src/main/java/com/example/tiptime/ui/theme/Theme.kt new file mode 100644 index 0000000..5c72303 --- /dev/null +++ b/app/src/main/java/com/example/tiptime/ui/theme/Theme.kt @@ -0,0 +1,31 @@ +package com.example.tiptime.ui.theme + +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color + +private val PrimaryBlue = Color(0xFF42A5F5) +private val SecondaryBlue = Color(0xFF90CAF9) +private val BackgroundWhite = Color(0xFFFFFFFF) +private val TextDark = Color(0xFF111111) + +private val LightColorScheme = lightColorScheme( + primary = PrimaryBlue, + onPrimary = Color.White, + secondary = SecondaryBlue, + onSecondary = Color.White, + background = BackgroundWhite, + surface = BackgroundWhite, + onBackground = TextDark, + onSurface = TextDark, +) + +@Composable +fun TipTimeTheme(content: @Composable () -> Unit) { + MaterialTheme( + colorScheme = LightColorScheme, + typography = Typography, + content = content + ) +} diff --git a/app/src/main/java/com/example/tiptime/ui/theme/Type.kt b/app/src/main/java/com/example/tiptime/ui/theme/Type.kt new file mode 100644 index 0000000..a4cf6e6 --- /dev/null +++ b/app/src/main/java/com/example/tiptime/ui/theme/Type.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.tiptime.ui.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + displaySmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Bold, + fontSize = 36.sp, + lineHeight = 44.sp, + letterSpacing = 0.sp, + ) +) diff --git a/app/src/main/res/drawable/bmilogo.png b/app/src/main/res/drawable/bmilogo.png new file mode 100644 index 0000000..1709491 Binary files /dev/null and b/app/src/main/res/drawable/bmilogo.png differ 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..ca3826a --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..4bda16c --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/kurusg.png b/app/src/main/res/drawable/kurusg.png new file mode 100644 index 0000000..f6e1375 Binary files /dev/null and b/app/src/main/res/drawable/kurusg.png differ diff --git a/app/src/main/res/drawable/normalg.png b/app/src/main/res/drawable/normalg.png new file mode 100644 index 0000000..17346b0 Binary files /dev/null and b/app/src/main/res/drawable/normalg.png differ diff --git a/app/src/main/res/drawable/number.xml b/app/src/main/res/drawable/number.xml new file mode 100644 index 0000000..9eaa138 --- /dev/null +++ b/app/src/main/res/drawable/number.xml @@ -0,0 +1,22 @@ + + + + + + diff --git a/app/src/main/res/drawable/obesitasg.png b/app/src/main/res/drawable/obesitasg.png new file mode 100644 index 0000000..f9e613a Binary files /dev/null and b/app/src/main/res/drawable/obesitasg.png differ diff --git a/app/src/main/res/drawable/overweightg.png b/app/src/main/res/drawable/overweightg.png new file mode 100644 index 0000000..085fe22 Binary files /dev/null and b/app/src/main/res/drawable/overweightg.png differ 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..c4a603d --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ 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..c4a603d --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ 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..7d78d23 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_foreground.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000..9329967 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.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..2074955 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..6ac43cb 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_foreground.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000..57f9f62 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.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..6ad3fdc 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..62e3616 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_foreground.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000..02a1722 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.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..996e109 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..4f8b89d 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_foreground.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000..da3189d Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.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..aaa0a8b 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..1ca4eb3 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_foreground.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000..943b0fd Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.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..ec91a08 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/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..04e6db2 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,25 @@ + + + + BMI Calculator + Calculate BMI + Tinggi Badan + Berat Badan + Gunakan Unit USC (lbs/in)? + BMI Anda: %s + Kategori: %s + diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..bbe5ce2 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,19 @@ + + + +