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/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b589d56 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..a2d7c21 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..69e8615 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..773fe0f --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ 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 b/app/build.gradle new file mode 100644 index 0000000..9dc51fb --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,57 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' + id 'com.google.gms.google-services' +} + +android { + namespace 'com.qdot.fitgo' + compileSdk 34 + + defaultConfig { + applicationId "com.qdot.fitgo" + minSdk 28 + targetSdk 34 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } + buildFeatures { + viewBinding true + } +} + +dependencies { + + implementation 'androidx.core:core-ktx:1.10.1' + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'com.google.android.material:material:1.9.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation 'androidx.navigation:navigation-fragment-ktx:2.6.0' + implementation 'androidx.navigation:navigation-ui-ktx:2.6.0' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.5' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' + implementation platform('com.google.firebase:firebase-bom:32.1.1') + implementation 'com.google.firebase:firebase-analytics-ktx' + implementation("com.google.firebase:firebase-auth-ktx") + implementation 'id.passage.android:passage:1.0.0' + implementation("com.github.kittinunf.fuel:fuel:3.0.0-alpha1") + + implementation "androidx.health.connect:connect-client:1.1.0-alpha02" +} \ No newline at end of file diff --git a/app/google-services.json b/app/google-services.json new file mode 100644 index 0000000..481105b --- /dev/null +++ b/app/google-services.json @@ -0,0 +1,47 @@ +{ + "project_info": { + "project_number": "216962382574", + "project_id": "fitgo-e355d", + "storage_bucket": "fitgo-e355d.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:216962382574:android:724134293882df3d2fd1ff", + "android_client_info": { + "package_name": "com.qdot.fitgo" + } + }, + "oauth_client": [ + { + "client_id": "216962382574-ke4km15vrj9p19lr8173110mn99gem7e.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "com.qdot.fitgo", + "certificate_hash": "217b604705642c34209bfc4151cf3cb7c4c7d4eb" + } + }, + { + "client_id": "216962382574-hnhroh907ie8ngbt7hedqee6v7urq2oh.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyAesYfg6xMDEyg9ALfhYq1Sz9qSqgs0SGc" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "216962382574-hnhroh907ie8ngbt7hedqee6v7urq2oh.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + } + ], + "configuration_version": "1" +} \ 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/qdot/fitgo/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/qdot/fitgo/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..4be6828 --- /dev/null +++ b/app/src/androidTest/java/com/qdot/fitgo/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.qdot.fitgo + +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.qdot.fitgo", 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..9c8a7fe --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png new file mode 100644 index 0000000..f3ab3f5 Binary files /dev/null and b/app/src/main/ic_launcher-playstore.png differ diff --git a/app/src/main/java/com/qdot/fitgo/AuthBottomSheet.kt b/app/src/main/java/com/qdot/fitgo/AuthBottomSheet.kt new file mode 100644 index 0000000..9e32d6d --- /dev/null +++ b/app/src/main/java/com/qdot/fitgo/AuthBottomSheet.kt @@ -0,0 +1,110 @@ +package com.qdot.fitgo + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import com.google.firebase.auth.FirebaseAuth +import com.qdot.fitgo.databinding.AuthSheetLayoutBinding +import fuel.Fuel +import fuel.get +import id.passage.android.Passage +import id.passage.android.exceptions.RegisterWithPasskeyException +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import org.json.JSONObject + +class AuthBottomSheet(private val passage: Passage, private val auth : FirebaseAuth, + private val loginInterface : LoginInterface) : BottomSheetDialogFragment() { + private var _binding: AuthSheetLayoutBinding? = null + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = AuthSheetLayoutBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + binding.loginNow.setOnClickListener { + if (binding.mobText.text.isNullOrEmpty()){ + Toast.makeText(requireContext(), + "Enter email", + Toast.LENGTH_SHORT).show() + } + else { + CoroutineScope(Dispatchers.IO).launch { + try { + passage.loginWithPasskey(binding.mobText.text.toString()) + val user = passage.getCurrentUser() ?: return@launch + loginWithFirebase(user.id!!,user.email!!) + } catch (e: RegisterWithPasskeyException) { + loginInterface.loginStatus(false,e.message.toString()) + dismiss() + } + } + } + } + + binding.signupNow.setOnClickListener { + if (binding.mobText.text.isNullOrEmpty()){ + Toast.makeText(requireContext(), + "Enter email", + Toast.LENGTH_SHORT).show() + } + else { + CoroutineScope(Dispatchers.IO).launch { + try { + passage.registerWithPasskey(binding.mobText.text.toString()) + val user = passage.getCurrentUser() ?: return@launch + loginWithFirebase(user.id!!,user.email!!) + } catch (e: RegisterWithPasskeyException) { + loginInterface.loginStatus(false,e.message.toString()) + dismiss() + } + } + } + } + } + + private suspend fun loginWithFirebase(id: String,email:String) { + try { + val responseDat = Fuel.get("https://iamtoken-1-g1882055.deta.app/user/create/$id").body + val jsonObject = JSONObject(responseDat) + if (jsonObject.getBoolean("ok")){ + auth.signInWithCustomToken(jsonObject.getString("data")) + .addOnCompleteListener { + if (it.isSuccessful){ + if (auth.currentUser?.email.isNullOrEmpty()) { + auth.currentUser?.updateEmail(email) + } + loginInterface.loginStatus(true,"") + dismiss() + }else{ + loginInterface.loginStatus(false,"FB auth is not completed") + dismiss() + } + } + }else{ + loginInterface.loginStatus(false,"Can not create token") + dismiss() + } + }catch (e:Exception){ + loginInterface.loginStatus(false,e.message.toString()) + dismiss() + } + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/qdot/fitgo/LoginInterface.kt b/app/src/main/java/com/qdot/fitgo/LoginInterface.kt new file mode 100644 index 0000000..ce5c755 --- /dev/null +++ b/app/src/main/java/com/qdot/fitgo/LoginInterface.kt @@ -0,0 +1,6 @@ +package com.qdot.fitgo + +interface LoginInterface { + fun loginStatus(loggedIn : Boolean,err : String) + fun logoutListener(loggedOut : Boolean) +} \ No newline at end of file diff --git a/app/src/main/java/com/qdot/fitgo/MainActivity.kt b/app/src/main/java/com/qdot/fitgo/MainActivity.kt new file mode 100644 index 0000000..b7e83fe --- /dev/null +++ b/app/src/main/java/com/qdot/fitgo/MainActivity.kt @@ -0,0 +1,224 @@ +package com.qdot.fitgo + +import android.annotation.SuppressLint +import android.os.Bundle +import android.view.View +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import androidx.health.connect.client.HealthConnectClient +import androidx.health.connect.client.PermissionController +import androidx.health.connect.client.permission.HealthPermission +import androidx.health.connect.client.records.DistanceRecord +import androidx.health.connect.client.records.HeartRateRecord +import androidx.health.connect.client.records.SpeedRecord +import androidx.health.connect.client.records.StepsRecord +import androidx.health.connect.client.records.TotalCaloriesBurnedRecord +import androidx.health.connect.client.records.WeightRecord +import androidx.health.connect.client.request.ReadRecordsRequest +import androidx.health.connect.client.time.TimeRangeFilter +import com.google.firebase.auth.FirebaseAuth +import com.google.firebase.auth.ktx.auth +import com.google.firebase.ktx.Firebase +import com.qdot.fitgo.databinding.ActivityMainBinding +import id.passage.android.Passage +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.time.LocalDateTime +import kotlin.math.roundToInt + +class MainActivity : AppCompatActivity(), LoginInterface { + private lateinit var binding: ActivityMainBinding + private lateinit var auth: FirebaseAuth + private lateinit var passage: Passage + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + auth = Firebase.auth + passage = Passage(this).also {pass -> + binding.loginBtn.setOnClickListener { + AuthBottomSheet(pass,auth,this).show(supportFragmentManager,"AUTH") + } + } + loadData() + + } + + override fun loginStatus(loggedIn: Boolean,err : String) { + if (loggedIn){ + loadData() + }else{ + CoroutineScope(Dispatchers.Main).launch{ + Toast.makeText(this@MainActivity, + err,Toast.LENGTH_SHORT).show() + } + } + } + + override fun logoutListener(loggedOut: Boolean) { + if (loggedOut){ + loadData() + } + } + + private fun checkHealthConnectIsAvailable(){ + val availabilityStatus = HealthConnectClient.getSdkStatus(this) + if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE) { + Toast.makeText(this,"Can not get data",Toast.LENGTH_SHORT).show() + return + } + val healthConnectClient = HealthConnectClient.getOrCreate(this) + CoroutineScope(Dispatchers.IO).launch { + checkPermissionsAndRun(healthConnectClient) + } + } + private val requestPermissionActivityContract = PermissionController.createRequestPermissionResultContract() + + private val requestPermissions = + registerForActivityResult(requestPermissionActivityContract) { granted -> + if (granted.containsAll(PERMISSIONS)) { + loadData() + } + } + + @SuppressLint("SetTextI18n") + private suspend fun checkPermissionsAndRun(healthConnectClient: HealthConnectClient) { + val granted = healthConnectClient.permissionController.getGrantedPermissions() + if (granted.containsAll(PERMISSIONS)) { + val timeEnd = LocalDateTime.now() + val timeStart = timeEnd.withHour(0) + .withMinute(0) + .withSecond(0) + .withNano(0) + + val requestSteps = ReadRecordsRequest( + recordType = StepsRecord::class, + timeRangeFilter = TimeRangeFilter.between(timeStart, timeEnd) + ) + val responseSteps = healthConnectClient.readRecords(requestSteps) + if (responseSteps.records.isNotEmpty()){ + val stepsNo = responseSteps.records.sumOf { it.count }.toString() + withContext(Dispatchers.Main){ + binding.stepsTv.text = stepsNo + } + } + + val requestDistance = ReadRecordsRequest( + recordType = DistanceRecord::class, + timeRangeFilter = TimeRangeFilter.between(timeStart, timeEnd) + ) + val responseDistance = healthConnectClient.readRecords(requestDistance) + if (responseDistance.records.isNotEmpty()){ + val distNo = (responseDistance.records.sumOf { it.distance.inKilometers }*100.0).roundToInt()/100.0 + withContext(Dispatchers.Main){ + binding.distanceTv.text = distNo.toString() + } + } + + val requestCal = ReadRecordsRequest( + recordType = TotalCaloriesBurnedRecord::class, + timeRangeFilter = TimeRangeFilter.between(timeStart, timeEnd) + ) + val responseCal = healthConnectClient.readRecords(requestCal) + if (responseCal.records.isNotEmpty()){ + val distNo = (responseCal.records[0].energy.inKilocalories*100.0).roundToInt()/100.0 + withContext(Dispatchers.Main){ + binding.energyTv.text = distNo.toString() + } + }else{ + withContext(Dispatchers.Main){ + binding.energyTv.text = "NA" + } + } + + val requestWeight = ReadRecordsRequest( + recordType = WeightRecord::class, + timeRangeFilter = TimeRangeFilter.between(timeStart, timeEnd) + ) + val responseWeight = healthConnectClient.readRecords(requestWeight) + if (responseWeight.records.isNotEmpty()){ + val distNo = (responseWeight.records.sumOf { it.weight.inKilograms }*100.0).roundToInt()/100.0 + withContext(Dispatchers.Main){ + binding.weightTv.text = distNo.toString() + } + }else{ + withContext(Dispatchers.Main){ + binding.weightTv.text = "NA" + } + } + + val requestHeart = ReadRecordsRequest( + recordType = HeartRateRecord::class, + timeRangeFilter = TimeRangeFilter.between(timeStart, timeEnd) + ) + val responseHeart = healthConnectClient.readRecords(requestHeart) + if (responseHeart.records.isNotEmpty()){ + val distNo = responseHeart.records[0].samples[0].beatsPerMinute + withContext(Dispatchers.Main){ + binding.heartRateTv.text = distNo.toString() + } + }else{ + withContext(Dispatchers.Main){ + binding.heartRateTv.text = "NA" + } + } + + val requestCycle = ReadRecordsRequest( + recordType = SpeedRecord::class, + timeRangeFilter = TimeRangeFilter.between(timeStart, timeEnd) + ) + val responseCycle = healthConnectClient.readRecords(requestCycle) + if (responseCycle.records.isNotEmpty()){ + val distNo = (responseCycle.records[0].samples[0].speed.inMetersPerSecond*100.0).roundToInt()/100.0 + withContext(Dispatchers.Main){ + binding.cycleDisTv.text = distNo.toString() + } + }else{ + withContext(Dispatchers.Main){ + binding.cycleDisTv.text = "00.0" + } + } + + } else { + requestPermissions.launch(PERMISSIONS) + } + } + + private fun loadData() { + CoroutineScope(Dispatchers.IO).launch { + val currentUser = passage.getCurrentUser() + if (currentUser != null) { + withContext(Dispatchers.Main) { + checkHealthConnectIsAvailable() + binding.userNameTv.text = currentUser.email + binding.loginLayout.visibility = View.GONE + binding.mainDataLayout.visibility = View.VISIBLE + binding.menuBtn.setOnClickListener { + SettingsBottomSheet(passage,auth,this@MainActivity) + .show(supportFragmentManager,"SET") + } + } + } else { + withContext(Dispatchers.Main) { + binding.loginLayout.visibility = View.VISIBLE + binding.mainDataLayout.visibility = View.GONE + } + } + } + } + + companion object{ + val PERMISSIONS = + setOf( + HealthPermission.getReadPermission(HeartRateRecord::class), + HealthPermission.getReadPermission(StepsRecord::class), + HealthPermission.getReadPermission(DistanceRecord::class), + HealthPermission.getReadPermission(TotalCaloriesBurnedRecord::class), + HealthPermission.getReadPermission(WeightRecord::class), + HealthPermission.getReadPermission(SpeedRecord::class) + ) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/qdot/fitgo/SettingsBottomSheet.kt b/app/src/main/java/com/qdot/fitgo/SettingsBottomSheet.kt new file mode 100644 index 0000000..feeb736 --- /dev/null +++ b/app/src/main/java/com/qdot/fitgo/SettingsBottomSheet.kt @@ -0,0 +1,66 @@ +package com.qdot.fitgo + +import android.annotation.SuppressLint +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.content.res.AppCompatResources +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import com.google.firebase.auth.FirebaseAuth +import com.qdot.fitgo.databinding.SettingsBottomSheetLayoutBinding +import id.passage.android.Passage +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class SettingsBottomSheet(private val passage: Passage,private val auth : FirebaseAuth,private val loginInterface : LoginInterface) : BottomSheetDialogFragment() { + private var _binding: SettingsBottomSheetLayoutBinding? = null + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = SettingsBottomSheetLayoutBinding.inflate(inflater, container, false) + return binding.root + } + + @SuppressLint("SetTextI18n") + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + CoroutineScope(Dispatchers.IO).launch { + val currentUser = passage.getCurrentUser()!! + withContext(Dispatchers.Main) { + binding.emailTv.text = currentUser.email + if (currentUser.emailVerified == true) { + binding.emailVerifyImg.setImageDrawable( + AppCompatResources.getDrawable( + requireContext(), + R.drawable.baseline_verified_24 + ) + ) + } + binding.joinedTv.text = + "Joined us on ${currentUser.createdAt.toString().substring(0, 11)}" + binding.loginCountTv.text = + "You have logged-in ${currentUser.loginCount} times with this account" + binding.logoutBtn.setOnClickListener { + CoroutineScope(Dispatchers.IO).launch { + passage.signOutCurrentUser() + loginInterface.logoutListener(true) + auth.signOut() + dismiss() + } + } + } + } + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/baseline_error_24.xml b/app/src/main/res/drawable/baseline_error_24.xml new file mode 100644 index 0000000..391e8b4 --- /dev/null +++ b/app/src/main/res/drawable/baseline_error_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/baseline_key_24.xml b/app/src/main/res/drawable/baseline_key_24.xml new file mode 100644 index 0000000..f49ad6f --- /dev/null +++ b/app/src/main/res/drawable/baseline_key_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/baseline_menu_24.xml b/app/src/main/res/drawable/baseline_menu_24.xml new file mode 100644 index 0000000..543cee9 --- /dev/null +++ b/app/src/main/res/drawable/baseline_menu_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/baseline_verified_24.xml b/app/src/main/res/drawable/baseline_verified_24.xml new file mode 100644 index 0000000..faafa97 --- /dev/null +++ b/app/src/main/res/drawable/baseline_verified_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/cycle_girl_ic.png b/app/src/main/res/drawable/cycle_girl_ic.png new file mode 100644 index 0000000..cb7da9f Binary files /dev/null and b/app/src/main/res/drawable/cycle_girl_ic.png differ diff --git a/app/src/main/res/drawable/dumbble_girl_ic.png b/app/src/main/res/drawable/dumbble_girl_ic.png new file mode 100644 index 0000000..f33310a Binary files /dev/null and b/app/src/main/res/drawable/dumbble_girl_ic.png differ diff --git a/app/src/main/res/drawable/face_male_ic.png b/app/src/main/res/drawable/face_male_ic.png new file mode 100644 index 0000000..f52e69e Binary files /dev/null and b/app/src/main/res/drawable/face_male_ic.png differ diff --git a/app/src/main/res/drawable/family_ic.png b/app/src/main/res/drawable/family_ic.png new file mode 100644 index 0000000..fbd87c7 Binary files /dev/null and b/app/src/main/res/drawable/family_ic.png differ diff --git a/app/src/main/res/drawable/heart_girl_ic.png b/app/src/main/res/drawable/heart_girl_ic.png new file mode 100644 index 0000000..2400504 Binary files /dev/null and b/app/src/main/res/drawable/heart_girl_ic.png differ diff --git a/app/src/main/res/drawable/jumpping_girl_ic.png b/app/src/main/res/drawable/jumpping_girl_ic.png new file mode 100644 index 0000000..d0f6fb9 Binary files /dev/null and b/app/src/main/res/drawable/jumpping_girl_ic.png differ diff --git a/app/src/main/res/drawable/running_girl_ic.png b/app/src/main/res/drawable/running_girl_ic.png new file mode 100644 index 0000000..7397c53 Binary files /dev/null and b/app/src/main/res/drawable/running_girl_ic.png differ diff --git a/app/src/main/res/drawable/sleep_girl_ic.png b/app/src/main/res/drawable/sleep_girl_ic.png new file mode 100644 index 0000000..7cfa5a3 Binary files /dev/null and b/app/src/main/res/drawable/sleep_girl_ic.png differ diff --git a/app/src/main/res/drawable/yoga_girl_1.png b/app/src/main/res/drawable/yoga_girl_1.png new file mode 100644 index 0000000..cf5f134 Binary files /dev/null and b/app/src/main/res/drawable/yoga_girl_1.png differ diff --git a/app/src/main/res/drawable/yoga_girl_2.png b/app/src/main/res/drawable/yoga_girl_2.png new file mode 100644 index 0000000..41deefd Binary files /dev/null and b/app/src/main/res/drawable/yoga_girl_2.png differ diff --git a/app/src/main/res/drawable/yoga_girl_3.png b/app/src/main/res/drawable/yoga_girl_3.png new file mode 100644 index 0000000..9f97a5f Binary files /dev/null and b/app/src/main/res/drawable/yoga_girl_3.png differ diff --git a/app/src/main/res/drawable/yoga_girl_4.png b/app/src/main/res/drawable/yoga_girl_4.png new file mode 100644 index 0000000..17ed305 Binary files /dev/null and b/app/src/main/res/drawable/yoga_girl_4.png differ diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..e84976b --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,609 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/auth_sheet_layout.xml b/app/src/main/res/layout/auth_sheet_layout.xml new file mode 100644 index 0000000..4f55e29 --- /dev/null +++ b/app/src/main/res/layout/auth_sheet_layout.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/settings_bottom_sheet_layout.xml b/app/src/main/res/layout/settings_bottom_sheet_layout.xml new file mode 100644 index 0000000..6f8dafc --- /dev/null +++ b/app/src/main/res/layout/settings_bottom_sheet_layout.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + \ 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..036d09b --- /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..036d09b --- /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.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..51e7134 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..46f1f8b Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..d6a0bc5 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..f3e735e Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..48b7e65 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..787a0df Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..633dd7e Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..7c3ce6b Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..779c64c Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..9911f3b Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..1d826a0 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..a08799f Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..cb7458d Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..25f975e Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..a27e99c Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml new file mode 100644 index 0000000..183cadc --- /dev/null +++ b/app/src/main/res/values-night/themes.xml @@ -0,0 +1,35 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..890ce4b --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,67 @@ + + + #ffa6d1 + #94416F + #FFFFFF + #FFD8E8 + #3D0027 + #804893 + #FFFFFF + #FAD7FF + #330045 + #984061 + #FFFFFF + #FFD9E2 + #3E001D + #BA1A1A + #FFDAD6 + #FFFFFF + #410002 + #FFFBFF + #1F1A1C + #FFFBFF + #1F1A1C + #F1DEE4 + #504348 + #827379 + #F9EEF0 + #352F31 + #FFAFD5 + #000000 + #94416F + #D4C2C8 + #000000 + #FFAFD5 + #5B113F + #782956 + #FFD8E8 + #EEB0FF + #4D1660 + #662F79 + #FAD7FF + #FFB1C8 + #5E1132 + #7B2949 + #FFD9E2 + #FFB4AB + #93000A + #690005 + #FFDAD6 + #1F1A1C + #EBE0E2 + #1F1A1C + #EBE0E2 + #504348 + #D4C2C8 + #9D8D92 + #1F1A1C + #EBE0E2 + #94416F + #000000 + #FFAFD5 + #504348 + #000000 + + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml new file mode 100644 index 0000000..310e40c --- /dev/null +++ b/app/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #FFC0EC + \ 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..1d918d4 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,16 @@ + + FitGo + ssdEHO9HXoGOVQyNh5GGcsfp + https://fitgo-e355d.firebaseapp.com + + [{ + \\"include\\": \\"https://@string/passage_auth_origin/.well-known/assetlinks.json\\" + }] + + en + true + Your behaviors during the day, and especially before bedtime, can have a major impact on your sleep. They can promote healthy sleep or contribute to sleeplessness. + Your daily routines – what you eat and drink, the medications you take, how you schedule your days and how you choose to spend your evenings – can significantly impact your quality of sleep. Even a few slight adjustments can, in some cases, mean the difference between sound sleep and a restless night. + The term “sleep hygiene” refers to a series of healthy sleep habits that can improve your ability to fall asleep and stay asleep. These habits can help improve your sleep health. When people struggle with insomnia, sleep hygiene is an important part of cognitive behavioral therapy (CBT), the most effective long-term treatment for people with chronic insomnia. CBT for insomnia can help you address the thoughts and behaviors that prevent you from sleeping well. It also includes techniques for stress reduction, relaxation and sleep schedule management. + If you have difficulty sleeping or want to improve your sleep, try following these healthy sleep habits. Talk to your medical provider if your sleep problem persists. You also can seek help from the sleep team at an AASM accredited sleep center. + \ 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..26e272b --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,37 @@ + + + + +