Skip to content

Commit

Permalink
Merge branch 'main' of github.com:PeriodPals/periodpals into feat/pro…
Browse files Browse the repository at this point in the history
…file/view-model
  • Loading branch information
Harrish92 committed Oct 17, 2024
2 parents 84e3de1 + 732bf97 commit 6aa0545
Show file tree
Hide file tree
Showing 41 changed files with 8,907 additions and 84 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ These new community features constitute a key innovation: users can discreetly r

## Links
[Figma](https://www.figma.com/team_invite/redeem/MnyBeEvw4fKH4aV5aVBpPb)
[Google Drive](https://docs.google.com/document/d/1-qGE7yrF2O_BGeR_vdvgo5ePdevHa0nPuL4w-9gv3MQ/edit?usp=sharing)
[Google Drive](https://docs.google.com/document/d/1-qGE7yrF2O_BGeR_vdvgo5ePdevHa0nPuL4w-9gv3MQ/edit?usp=sharing)
[Architecture Diagram on Excalidraw](https://excalidraw.com/#json=lnlBs2IsbkRrnxmz0vlL1,VML2k7MzPW-Jo9j7Nq6rmQ)
Empty file added app/.attach_pid3458
Empty file.
29 changes: 5 additions & 24 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ android {
namespace = "com.android.periodpals"
compileSdk = 34



defaultConfig {
applicationId = "com.android.periodpals"
minSdk = 28
Expand All @@ -45,19 +43,9 @@ android {
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}

// Load the API keys from the local.properties file
val localProperties = Properties()
val localPropertiesFile = rootProject.file("local.properties")
localProperties.load(FileInputStream(localPropertiesFile))

val supabaseUrl = localProperties.getProperty("SUPABASE_URL") ?: ""
val supabaseKey = localProperties.getProperty("SUPABASE_KEY") ?: ""

debug {
enableUnitTestCoverage = true
enableAndroidTestCoverage = true
resValue("string", "SUPABASE_URL", localProperties[supabaseUrl].toString())
resValue("string", "SUPABASE_KEY", localProperties[supabaseKey].toString())
}
}

Expand Down Expand Up @@ -163,16 +151,8 @@ dependencies {
// implementation(libs.androidx.appcompat)
// implementation(libs.androidx.constraintlayout)
// implementation(libs.androidx.fragment.ktx)

// implementation(libs.kotlinx.serialization.json)

implementation(libs.mockk.v1120)
implementation(libs.firebase.firestore.ktx)
// required if you want to use Mockito for unit tests
testImplementation(libs.mockito.core.v2245)
// required if you want to use Mockito for Android tests
androidTestImplementation(libs.mockito.android.v2245)

implementation(libs.compose)
implementation(libs.mockk.v1120)
implementation(libs.androidx.ui.test.junit4.v105)
Expand Down Expand Up @@ -241,11 +221,14 @@ dependencies {
testImplementation(libs.mockito.kotlin)
testImplementation(libs.mockito.core.v540)

testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.1")

// OpenStreetMap (osmdroid) dependency
implementation("org.osmdroid:osmdroid-android:6.1.13")
// Location Services
implementation("com.google.android.gms:play-services-location:21.0.1")
}



tasks.withType<Test> {
// Configure Jacoco for each tests
configure<JacocoTaskExtension> {
Expand Down Expand Up @@ -286,5 +269,3 @@ tasks.register("jacocoTestReport", JacocoReport::class) {
include("outputs/code_coverage/debugAndroidTest/connected/*/coverage.ec")
})
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.android.periodpals

import android.Manifest
import android.content.pm.PackageManager
import androidx.core.content.ContextCompat
import androidx.test.core.app.ActivityScenario
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.rule.GrantPermissionRule
import org.junit.Assert.assertTrue
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class MainActivityTest {

@get:Rule
val permissionRule: GrantPermissionRule =
GrantPermissionRule.grant(Manifest.permission.ACCESS_FINE_LOCATION)

@Test
fun testLocationPermissionGranted() {
val scenario = ActivityScenario.launch(MainActivity::class.java)
scenario.onActivity { activity ->
val permissionStatus =
ContextCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION)
assertTrue(permissionStatus == PackageManager.PERMISSION_GRANTED)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.android.periodpals.ui.map

// UI test for MapViewContainer.kt

import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import com.android.periodpals.ui.theme.PeriodPalsAppTheme
import org.junit.Rule
import org.junit.Test

class MapScreenTest {

@get:Rule val composeTestRule = createComposeRule()

@Test
fun testMapScreenWithPermissionGranted() {
composeTestRule.setContent {
PeriodPalsAppTheme { MapScreen(locationPermissionGranted = true) }
}
// Verify that the map is displayed when permission is granted
composeTestRule.onNodeWithTag("MapView").assertExists()
}

@Test
fun testMapScreenWithoutPermission() {
composeTestRule.setContent {
PeriodPalsAppTheme { MapScreen(locationPermissionGranted = false) }
}
// Verify that the map is still displayed even if permission is not granted
composeTestRule.onNodeWithTag("MapView").assertExists()
}
}
3 changes: 3 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />


<application
android:allowBackup="true"
Expand Down
Binary file added app/src/main/ic_launcher-playstore.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
59 changes: 57 additions & 2 deletions app/src/main/java/com/android/periodpals/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ package com.android.periodpals
// import androidx.navigation.navigation
// import com.android.periodpals.ui.navigation.Route
// import com.android.periodpals.ui.navigation.Screen
import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
Expand All @@ -22,7 +26,10 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.navigation.compose.rememberNavController
import com.android.periodpals.ui.map.MapScreen
import com.android.periodpals.model.user.UserRepositorySupabase
import com.android.periodpals.model.user.UserViewModel
import com.android.periodpals.ui.navigation.NavigationActions
Expand All @@ -32,26 +39,74 @@ import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.Serializable
import org.osmdroid.config.Configuration

class MainActivity : ComponentActivity() {


var locationPermissionGranted by mutableStateOf(false)

// Constants for request codes
companion object {
private const val LOCATION_PERMISSION_REQUEST_CODE = 1
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

// Initialize osmdroid configuration
Configuration.getInstance().load(this, getSharedPreferences("osmdroid", Context.MODE_PRIVATE))

setContent {
PeriodPalsAppTheme {
// A surface container using the 'background' color from the theme
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
PeriodPalsApp()
PeriodPalsApp(locationPermissionGranted)
}
}
}

// Check and request location permission
checkLocationPermission()
}
// Check if location permission is granted or request it if not
private fun checkLocationPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) ==
PackageManager.PERMISSION_GRANTED) {
// **Permission is granted, update state**
locationPermissionGranted = true
} else {
// **Request permission**
ActivityCompat.requestPermissions(
this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), LOCATION_PERMISSION_REQUEST_CODE)
}
}

// Handle permission result and check if permission was granted
@Deprecated("Deprecated in Java")
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == LOCATION_PERMISSION_REQUEST_CODE &&
grantResults.isNotEmpty() &&
grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// **Permission granted, update state**
locationPermissionGranted = true
} else {
// **Permission denied, notify user**
Toast.makeText(this, "Location permission denied.", Toast.LENGTH_SHORT).show()
}
}
}

@Composable
fun PeriodPalsApp() {
fun PeriodPalsApp(locationPermissionGranted: Boolean) {
val navController = rememberNavController()
val navigationActions = NavigationActions(navController)
//MapScreen(Modifier.fillMaxSize(), locationPermissionGranted)
val db = UserViewModel(UserRepositorySupabase())
CreateProfile(db)
// CountriesList()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.android.periodpals.model

import io.github.jan.supabase.auth.Auth
import io.github.jan.supabase.createSupabaseClient
import io.github.jan.supabase.postgrest.Postgrest

object SupabaseClient {
val client =
Expand All @@ -11,6 +10,5 @@ object SupabaseClient {
supabaseKey = System.getenv("SUPABASE_KEY") ?: "",
) {
install(Auth)
install(Postgrest)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,13 @@ class AuthModelSupabase(
onFailure: (Exception) -> Unit,
) {
try {
supabaseAuth.retrieveUser(token)
supabaseAuth.refreshCurrentSession() // will throw an error if the user is not logged in
Log.d(TAG, "isUserLoggedIn: user is logged in")
onSuccess()
if (null != supabaseAuth.currentUserOrNull()) {
onSuccess()
} else {
onFailure(Exception("Not logged in"))
}
} catch (e: Exception) {
Log.d(TAG, "isUserLoggedIn: user is not logged in: ${e.message}")
Log.d(TAG, "logout: failed to log out the user: ${e.message}")
onFailure(e)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package com.android.periodpals.model.auth

import android.content.Context
import android.util.Log
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.android.periodpals.model.user.UserAuthState
import kotlinx.coroutines.launch

private const val TAG = "AuthViewModel"

class AuthViewModel(private val authModel: AuthModel) : ViewModel() {

private val _userAuthState = mutableStateOf<UserAuthState>(UserAuthState.Loading)
val userAuthState: State<UserAuthState> = _userAuthState

fun signUpWithEmail(context: Context, userEmail: String, userPassword: String) {
_userAuthState.value = UserAuthState.Loading
viewModelScope.launch {
authModel.register(
userEmail = userEmail,
userPassword = userPassword,
onSuccess = {
Log.d(TAG, "signUpWithEmail: registered user successfully")
_userAuthState.value = UserAuthState.Success("Registered user successfully")
},
onFailure = { e: Exception ->
Log.d(TAG, "signUpWithEmail: failed to register user: $e")
_userAuthState.value = UserAuthState.Error("Error: $e")
},
)
}
}

fun logInWithEmail(context: Context, userEmail: String, userPassword: String) {
_userAuthState.value = UserAuthState.Loading
viewModelScope.launch {
authModel.login(
userEmail = userEmail,
userPassword = userPassword,
onSuccess = {
Log.d(TAG, "logInWithEmail: logged in successfully")
_userAuthState.value = UserAuthState.Success("Logged in successfully")
},
onFailure = { e: Exception ->
Log.d(TAG, "logInWithEmail: failed to log in: $e")
_userAuthState.value = UserAuthState.Error("Error: $e")
},
)
}
}

fun logOut(context: Context) {
// val sharedPreferenceHelper = SharedPreferenceHelper(context)
_userAuthState.value = UserAuthState.Loading
viewModelScope.launch {
authModel.logout(
onSuccess = {
Log.d(TAG, "logOut: logged out successfully")
// sharedPreferenceHelper.clearPreferences()
_userAuthState.value = UserAuthState.Success("Logged out successfully")
},
onFailure = { e: Exception ->
Log.d(TAG, "logOut: failed to log out: $e")
_userAuthState.value = UserAuthState.Error("Error: $e")
},
)
}
}

fun isUserLoggedIn(context: Context) {
viewModelScope.launch {
// call model for this ofc
authModel.isUserLoggedIn(
token = "",
onSuccess = {
Log.d(TAG, "isUserLoggedIn: user is confirmed logged in")
_userAuthState.value = UserAuthState.Success("User is logged in")
},
onFailure = {
Log.d(TAG, "isUserLoggedIn: user is not logged in")
_userAuthState.value = UserAuthState.Error("User is not logged in")
})
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.android.periodpals.model.user

sealed class UserAuthState {
data object Loading : UserAuthState()

data class Success(val message: String) : UserAuthState()

data class Error(val message: String) : UserAuthState()
}
Loading

0 comments on commit 6aa0545

Please sign in to comment.