Skip to content

Commit

Permalink
style: ktfmt
Browse files Browse the repository at this point in the history
  • Loading branch information
lazarinibruno committed Dec 19, 2024
2 parents 6261efc + 3969efc commit 40a0107
Show file tree
Hide file tree
Showing 48 changed files with 1,418 additions and 560 deletions.
12 changes: 12 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ dependencies {
testImplementation(libs.junit)
testImplementation(libs.mockito.kotlin)
testImplementation(libs.robolectric)
androidTestImplementation(platform(libs.compose.bom))
androidTestImplementation(libs.androidx.ui.test.junit4.v105)
globalTestImplementation(libs.androidx.junit)
globalTestImplementation(libs.androidx.espresso.core)

Expand Down Expand Up @@ -253,6 +255,16 @@ dependencies {

// Live Data
implementation(libs.androidx.runtime.livedata)

// StreamChatSDK
implementation(libs.stream.chat.android.offline.v660)
implementation(libs.stream.chat.android.compose.v660)
implementation(libs.stream.chat.android.ui.components.v660)

// java-jwt library
implementation(libs.java.jwt)


}

secrets {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ package com.android.periodpals.services

import android.Manifest
import androidx.activity.ComponentActivity
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.Lifecycle
import androidx.test.core.app.ActivityScenario
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.rule.GrantPermissionRule
import com.android.periodpals.model.authentication.AuthenticationViewModel
import com.android.periodpals.model.location.Location
import com.android.periodpals.model.user.AuthenticationUserData
import com.android.periodpals.model.user.UserViewModel
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.runTest
Expand All @@ -17,6 +20,7 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.mock
import org.mockito.Mockito.`when`

@RunWith(AndroidJUnit4::class)
class GPSServiceImplInstrumentedTest {
Expand All @@ -31,6 +35,7 @@ class GPSServiceImplInstrumentedTest {
private lateinit var scenario: ActivityScenario<ComponentActivity>
private lateinit var activity: ComponentActivity
private lateinit var gpsService: GPSServiceImpl
private lateinit var authenticationViewModel: AuthenticationViewModel
private lateinit var userViewModel: UserViewModel

// Default location
Expand All @@ -39,6 +44,7 @@ class GPSServiceImplInstrumentedTest {

@Before
fun setup() {
authenticationViewModel = mock(AuthenticationViewModel::class.java)
userViewModel = mock(UserViewModel::class.java)

scenario = ActivityScenario.launch(ComponentActivity::class.java)
Expand All @@ -49,15 +55,20 @@ class GPSServiceImplInstrumentedTest {

scenario.onActivity { activity ->
this.activity = activity
gpsService = GPSServiceImpl(this.activity, userViewModel)
gpsService = GPSServiceImpl(this.activity, authenticationViewModel, userViewModel)
}

// Once the GPSService has been initialized, set its state to resumed
scenario.moveToState(Lifecycle.State.RESUMED)

`when`(authenticationViewModel.authUserData)
.thenReturn(mutableStateOf(AuthenticationUserData("test", "test")))
}

@After
fun tearDownService() {
`when`(authenticationViewModel.authUserData)
.thenReturn(mutableStateOf(AuthenticationUserData("test", "test")))
gpsService.cleanup()
}

Expand Down
83 changes: 75 additions & 8 deletions app/src/main/java/com/android/periodpals/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
Expand All @@ -35,7 +38,6 @@ import com.android.periodpals.ui.alert.CreateAlertScreen
import com.android.periodpals.ui.alert.EditAlertScreen
import com.android.periodpals.ui.authentication.SignInScreen
import com.android.periodpals.ui.authentication.SignUpScreen
import com.android.periodpals.ui.chat.ChatScreen
import com.android.periodpals.ui.map.MapScreen
import com.android.periodpals.ui.navigation.NavigationActions
import com.android.periodpals.ui.navigation.Route
Expand All @@ -47,14 +49,24 @@ import com.android.periodpals.ui.settings.SettingsScreen
import com.android.periodpals.ui.theme.PeriodPalsAppTheme
import com.android.periodpals.ui.timer.TimerScreen
import com.google.android.gms.common.GoogleApiAvailability
import io.getstream.chat.android.client.ChatClient
import io.getstream.chat.android.client.logger.ChatLogLevel
import io.getstream.chat.android.compose.ui.channels.ChannelsScreen
import io.getstream.chat.android.compose.ui.theme.ChatTheme
import io.getstream.chat.android.models.InitializationState
import io.getstream.chat.android.offline.plugin.factory.StreamOfflinePluginFactory
import io.getstream.chat.android.state.plugin.config.StatePluginConfig
import io.getstream.chat.android.state.plugin.factory.StreamStatePluginFactory
import io.github.jan.supabase.auth.Auth
import io.github.jan.supabase.createSupabaseClient
import io.github.jan.supabase.postgrest.Postgrest
import io.github.jan.supabase.storage.Storage
import org.osmdroid.config.Configuration

class MainActivity : ComponentActivity() {
private const val TAG = "MainActivity"
private const val CHANNEL_SCREEN_TITLE = "Your Chats"

class MainActivity : ComponentActivity() {
private lateinit var gpsService: GPSServiceImpl
private lateinit var pushNotificationsService: PushNotificationsServiceImpl
private lateinit var chatViewModel: ChatViewModel
Expand All @@ -80,13 +92,15 @@ class MainActivity : ComponentActivity() {
private val alertViewModel = AlertViewModel(alertModel)

private val timerModel = TimerRepositorySupabase(supabaseClient)

private lateinit var timerViewModel: TimerViewModel

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

gpsService = GPSServiceImpl(this, userViewModel)
pushNotificationsService = PushNotificationsServiceImpl(this, userViewModel)
gpsService = GPSServiceImpl(this, authenticationViewModel, userViewModel)
pushNotificationsService =
PushNotificationsServiceImpl(this, authenticationViewModel, userViewModel)
timerManager = TimerManager(this)
timerViewModel = TimerViewModel(timerModel, timerManager)

Expand All @@ -96,7 +110,22 @@ class MainActivity : ComponentActivity() {
// Check if Google Play Services are available
GoogleApiAvailability.getInstance().makeGooglePlayServicesAvailable(this)

chatViewModel = ChatViewModel()
// Set up the OfflinePlugin for offline storage
val offlinePluginFactory =
StreamOfflinePluginFactory(
appContext = applicationContext,
)
val statePluginFactory =
StreamStatePluginFactory(config = StatePluginConfig(), appContext = this)

// Set up the chat client for API calls and with the plugin for offline storage
val chatClient =
ChatClient.Builder(BuildConfig.STREAM_SDK_KEY, applicationContext)
.withPlugins(offlinePluginFactory, statePluginFactory)
.logLevel(ChatLogLevel.ALL) // Set to NOTHING in prod
.build()

chatViewModel = ChatViewModel(chatClient)

setContent {
PeriodPalsAppTheme {
Expand All @@ -109,6 +138,7 @@ class MainActivity : ComponentActivity() {
userViewModel,
alertViewModel,
timerViewModel,
chatClient,
chatViewModel,
)
}
Expand Down Expand Up @@ -159,7 +189,8 @@ fun PeriodPalsApp(
userViewModel: UserViewModel,
alertViewModel: AlertViewModel,
timerViewModel: TimerViewModel,
chatViewModel: ChatViewModel,
chatClient: ChatClient,
chatViewModel: ChatViewModel
) {
val navController = rememberNavController()
val navigationActions = NavigationActions(navController)
Expand Down Expand Up @@ -203,7 +234,37 @@ fun PeriodPalsApp(
composable(Screen.EDIT_ALERT) {
EditAlertScreen(locationViewModel, gpsService, alertViewModel, navigationActions)
}
composable(Screen.CHAT) { ChatScreen(chatViewModel, navigationActions) }

composable(Screen.CHAT) {
val clientInitialisationState by chatClient.clientState.initializationState.collectAsState()
val clientConnectionState by chatClient.clientState.connectionState.collectAsState()
val context = LocalContext.current

Log.d(TAG, "Client initialization state: $clientInitialisationState")

ChatTheme {
when (clientInitialisationState) {
InitializationState.COMPLETE -> {
Log.d(TAG, "Client initialization completed")
Log.d(TAG, "Client connection state $clientConnectionState")
ChannelsScreen(
title = CHANNEL_SCREEN_TITLE,
isShowingHeader = true,
onChannelClick = {
/** TODO: implement channels here */
},
onBackPressed = { navigationActions.navigateTo(Screen.ALERT_LIST) },
)
}
InitializationState.INITIALIZING -> {
Log.d(TAG, "Client initializing")
}
InitializationState.NOT_INITIALIZED -> {
Log.d(TAG, "Client not initialized yet.")
}
}
}
}
}

// Map
Expand All @@ -228,7 +289,13 @@ fun PeriodPalsApp(
// Profile
navigation(startDestination = Screen.PROFILE, route = Route.PROFILE) {
composable(Screen.PROFILE) {
ProfileScreen(userViewModel, pushNotificationsService, navigationActions)
ProfileScreen(
userViewModel,
authenticationViewModel,
pushNotificationsService,
chatViewModel,
navigationActions,
)
}
composable(Screen.EDIT_PROFILE) { EditProfileScreen(userViewModel, navigationActions) }
composable(Screen.SETTINGS) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,59 @@
package com.android.periodpals.model.chat

/** ViewModel for managing chat-related data and operations. */
class ChatViewModel {}
import android.util.Log
import androidx.lifecycle.ViewModel
import com.android.periodpals.model.authentication.AuthenticationViewModel
import com.android.periodpals.model.user.User
import com.android.periodpals.services.JwtTokenService
import io.getstream.chat.android.client.ChatClient

private const val TAG = "ChatViewModel"

/**
* View model for the chat feature.
*
* @property chatClient The client used for connecting to the Stream Chat service.
*/
class ChatViewModel(private val chatClient: ChatClient) : ViewModel() {

/**
* Connects the user to the Stream Chat service.
*
* @param profile The user's profile information.
* @param authenticationViewModel The ViewModel used for authentication.
* @param onSuccess Callback function to be called on successful connection.
* @param onFailure Callback function to be called on connection failure, with the exception as a
* parameter.
*/
fun connectUser(
profile: User?,
authenticationViewModel: AuthenticationViewModel,
onSuccess: () -> Unit = { Log.d(TAG, "User connected successfully.") },
onFailure: (Exception) -> Unit = { Log.d(TAG, "Failed to connect user: ${it.message}") },
) {
if (profile == null || authenticationViewModel.authUserData.value == null) {
Log.d(TAG, "Failed to connect user: profile or authentication data is null.")
onFailure(RuntimeException("Profile or authentication data is null."))
return
}

val uid = authenticationViewModel.authUserData.value!!.uid
JwtTokenService.generateStreamToken(
uid = uid,
onSuccess = {
val token = it
val userImage = profile.imageUrl.ifEmpty { "https://bit.ly/2TIt8NR" }
val user =
io.getstream.chat.android.models.User(
id = uid, name = profile.name, image = userImage)

chatClient.connectUser(user = user, token = token).enqueue()
Log.d(TAG, "User connected successfully.")
onSuccess()
},
onFailure = {
Log.d(TAG, "Failed to generate token.")
onFailure(it)
})
}
}
19 changes: 17 additions & 2 deletions app/src/main/java/com/android/periodpals/model/user/UserModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,25 @@ interface UserRepository {
/**
* Loads the user profile for the given user ID.
*
* @param idUser The ID of the user profile to be loaded.
* @param onSuccess callback to be called on successful call on this function returning the
* UserDto
* @param onFailure callback to be called when error is caught
*/
suspend fun loadUserProfile(onSuccess: (UserDto) -> Unit, onFailure: (Exception) -> Unit)
suspend fun loadUserProfile(
idUser: String,
onSuccess: (UserDto) -> Unit,
onFailure: (Exception) -> Unit
)

/**
* Loads all user profiles.
*
* @param onSuccess callback to be called on successful call on this function returning the list
* of UserDto
* @param onFailure callback to be called when error is caught
*/
suspend fun loadUserProfiles(onSuccess: (List<UserDto>) -> Unit, onFailure: (Exception) -> Unit)

/**
* Creates the user profile.
Expand All @@ -25,7 +39,8 @@ interface UserRepository {
* else create new.
*
* @param userDto The user profile to be checked
* @param onSuccess callback block
* @param onSuccess callback block to be called on success
* @param onFailure callback block to be called when exception is caught
*/
suspend fun upsertUserProfile(
userDto: UserDto,
Expand Down
Loading

0 comments on commit 40a0107

Please sign in to comment.