Skip to content

Commit

Permalink
Merge pull request #598 from bounswe/feature/mobile-394-notification-…
Browse files Browse the repository at this point in the history
…page

Feature/mobile 394 notification page
  • Loading branch information
HarunErgen authored Dec 23, 2023
2 parents 8ff756c + 8af726e commit fd2a195
Show file tree
Hide file tree
Showing 5 changed files with 229 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import com.cmpe451.resq.ui.theme.LightGreen
import com.cmpe451.resq.ui.theme.ResQTheme
import com.cmpe451.resq.ui.views.screens.LoginScreen
import com.cmpe451.resq.ui.views.screens.MapScreen
import com.cmpe451.resq.ui.views.screens.NotificationScreen
import com.cmpe451.resq.ui.views.screens.OngoingTasksScreen
import com.cmpe451.resq.ui.views.screens.ProfileScreen
import com.cmpe451.resq.ui.views.screens.RegistrationScreen
Expand Down Expand Up @@ -143,7 +144,7 @@ fun NavGraph(
ProfileScreen(navController, appContext)
}
composable(NavigationItem.Notifications.route) {
//NotificationsScreen(navController)
NotificationScreen(navController, appContext)
}
composable(NavigationItem.Settings.route) {
SettingsScreen(navController, appContext)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.cmpe451.resq.data.models

data class NotificationItem(
val id: Int,
val createdAt: String,
val modifiedAt: String,
val userId: Int,
val title: String,
val body: String,
val relatedEntityId: Int,
val notificationType: String,
val read: Boolean
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.cmpe451.resq.data.remote

import android.content.Context
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import com.cmpe451.resq.data.Constants
import com.cmpe451.resq.data.manager.UserSessionManager
Expand All @@ -11,6 +12,7 @@ import com.cmpe451.resq.data.models.CreateResourceRequestBody
import com.cmpe451.resq.data.models.LoginRequestBody
import com.cmpe451.resq.data.models.LoginResponse
import com.cmpe451.resq.data.models.Need
import com.cmpe451.resq.data.models.NotificationItem
import com.cmpe451.resq.data.models.ProfileData
import com.cmpe451.resq.data.models.RegisterRequestBody
import com.cmpe451.resq.data.models.UserInfoRequest
Expand Down Expand Up @@ -96,6 +98,14 @@ interface ProfileService {

}

interface NotificationService {
@GET("notification/viewAllNotifications")
suspend fun getNotifications(
@Query("userId") userId: Int,
@Header("Authorization") jwtToken: String
): Response<List<NotificationItem>>
}

class ResqService(appContext: Context) {

var gson = GsonBuilder()
Expand All @@ -112,6 +122,7 @@ class ResqService(appContext: Context) {
private val needService: NeedService = retrofit.create(NeedService::class.java)
private val authService: AuthService = retrofit.create(AuthService::class.java)
private val profileService: ProfileService = retrofit.create(ProfileService::class.java)
private val notificationService: NotificationService = retrofit.create(NotificationService::class.java)

private val userSessionManager: UserSessionManager = UserSessionManager.getInstance(appContext)

Expand Down Expand Up @@ -267,4 +278,15 @@ class ResqService(appContext: Context) {

return response
}

suspend fun getNotifications(): Response<List<NotificationItem>> {
val userId = userSessionManager.getUserId()
val token = userSessionManager.getUserToken() ?: ""
val response = notificationService.getNotifications(
userId = userId,
jwtToken = "Bearer $token",
)
Log.d("AAA", "getNotifications: ${response.isSuccessful}")
return response
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package com.cmpe451.resq.ui.views.screens

import android.annotation.SuppressLint
import android.content.Context
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.Card
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Scaffold
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AccountCircle
import androidx.compose.material.icons.filled.Notifications
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.cmpe451.resq.data.models.NotificationItem
import com.cmpe451.resq.viewmodels.NotificationViewModel

@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
@Composable
fun NotificationScreen(navController: NavController, appContext: Context) {
val viewModel = NotificationViewModel(appContext)
val notifications by viewModel.notificationItems

Scaffold(
topBar = {
TopAppBar(
title = { Text("Notifications") },
navigationIcon = {
Icon(
Icons.Default.Notifications,
contentDescription = "Notifications"
)
},
backgroundColor = Color.White,
contentColor = Color.Black
)
}
) {
NotificationList(notifications)
}
}

@Composable
fun NotificationList(notificationItems: List<NotificationItem>) {
LazyColumn {
items(notificationItems) { item ->
NotificationItemCard(item)
}
}
}

@Composable
fun NotificationItemCard(notification: NotificationItem) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
elevation = 2.dp
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Row(
verticalAlignment = Alignment.CenterVertically
) {
// Replace this with an actual image using Coil or other image loading library
Icon(
Icons.Default.AccountCircle,
contentDescription = "Profile",
modifier = Modifier.size(40.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Column {
Text(
text = notification.title,
fontWeight = FontWeight.Bold
)
Text(
text = notification.createdAt,
style = MaterialTheme.typography.body2
)
}
}
Spacer(modifier = Modifier.height(8.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = notification.body,
style = MaterialTheme.typography.body2
)
/*
if (notification.isActionable) {
Button(onClick = { /* TODO: Handle View action */ }) {
Text("VIEW")
}
}
*/
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.cmpe451.resq.viewmodels

import android.content.Context
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.cmpe451.resq.data.models.NotificationItem
import com.cmpe451.resq.data.remote.ResqService
import kotlinx.coroutines.launch

class NotificationViewModel(appContext: Context) : ViewModel() {

private val _notificationItems by lazy { mutableStateOf<List<NotificationItem>>(listOf()) }
val notificationItems: State<List<NotificationItem>> = _notificationItems

init {
fetchNotifications(appContext)
}

private fun fetchNotifications(appContext: Context) {
viewModelScope.launch {
/*
val notifications = getNotifications(appContext)
notifications.getOrNull()?.let {
_notificationItems.value = it
}
*/
val notifications =
listOf(
NotificationItem(
id = 1,
createdAt = "2021-05-01T00:00:00.000Z",
modifiedAt = "2021-05-01T00:00:00.000Z",
userId = 1,
title = "Notification Title",
body = "Notification Body",
relatedEntityId = 1,
notificationType = "Notification Type",
read = false
),
NotificationItem(
id = 2,
createdAt = "2021-05-01T00:00:00.000Z",
modifiedAt = "2021-05-01T00:00:00.000Z",
userId = 1,
title = "Notification Title",
body = "Notification Body",
relatedEntityId = 1,
notificationType = "Notification Type",
read = false
),
)
_notificationItems.value = notifications

}
}

suspend fun getNotifications(appContext: Context): Result<List<NotificationItem>> {
val api = ResqService(appContext)
val response = api.getNotifications()
if (response.isSuccessful) {
response.body()?.let {
return Result.success(it)
}
}
return Result.failure(Throwable(response.message()))
}
}

0 comments on commit fd2a195

Please sign in to comment.