From 046da599b7a614501fa9d0c136769a211178ae98 Mon Sep 17 00:00:00 2001 From: Peter Vacho Date: Sat, 4 Jan 2025 13:15:34 +0100 Subject: [PATCH] feat(notifications): Fetch corresponding invitations --- .../activities/NotificationsActivity.kt | 20 ++++++- .../adapters/NotificationAdapter.kt | 52 ++++++++++++++----- .../api/models/InvitationModels.kt | 12 +++++ .../api/services/InvitationsService.kt | 21 +++++++- 4 files changed, 91 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/p_vacho/neat_calendar/activities/NotificationsActivity.kt b/app/src/main/java/com/p_vacho/neat_calendar/activities/NotificationsActivity.kt index fa9ecc7..f9bd00b 100644 --- a/app/src/main/java/com/p_vacho/neat_calendar/activities/NotificationsActivity.kt +++ b/app/src/main/java/com/p_vacho/neat_calendar/activities/NotificationsActivity.kt @@ -14,6 +14,7 @@ import com.p_vacho.neat_calendar.MyApplication import com.p_vacho.neat_calendar.R import com.p_vacho.neat_calendar.adapters.NotificationAdapter import com.p_vacho.neat_calendar.api.RetrofitClient +import com.p_vacho.neat_calendar.api.models.InvitationResponse import com.p_vacho.neat_calendar.api.models.NotificationResponse import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -24,6 +25,7 @@ class NotificationsActivity : AppCompatActivity() { private lateinit var btnBack: ImageButton private lateinit var notifications: MutableList + private lateinit var invitations: MutableMap // invitation id -> invitation override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -43,7 +45,10 @@ class NotificationsActivity : AppCompatActivity() { lifecycleScope.launch { notifications = fetchNotifications().toMutableList() - rvNotifications.adapter = NotificationAdapter(notifications, ::handleNotificationAction, ::handleNotificationClick) + invitations = fetchInvitations().toMutableMap() + rvNotifications.adapter = NotificationAdapter(notifications, ::handleNotificationAction, ::handleNotificationClick) { + notification -> invitations[notification.data] + } } btnBack.setOnClickListener { finish() } @@ -64,6 +69,19 @@ class NotificationsActivity : AppCompatActivity() { return notifications } + private suspend fun fetchInvitations(): Map { + val userId = (application as MyApplication).tokenManager.userId + if (userId == null) { + finish() + return emptyMap() + } + + val fetchedInvitations = withContext(Dispatchers.IO) { + RetrofitClient.invitationService.getIncomingInvitations(userId) + } + return fetchedInvitations.associateBy { it.id } + } + private fun handleNotificationAction(notification: NotificationResponse, action: NotificationAdapter.Action, position: Int) { when (action) { NotificationAdapter.Action.ACCEPT -> { diff --git a/app/src/main/java/com/p_vacho/neat_calendar/adapters/NotificationAdapter.kt b/app/src/main/java/com/p_vacho/neat_calendar/adapters/NotificationAdapter.kt index ad3284f..4acf486 100644 --- a/app/src/main/java/com/p_vacho/neat_calendar/adapters/NotificationAdapter.kt +++ b/app/src/main/java/com/p_vacho/neat_calendar/adapters/NotificationAdapter.kt @@ -3,11 +3,11 @@ package com.p_vacho.neat_calendar.adapters import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.Button import android.widget.ImageButton import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import com.p_vacho.neat_calendar.R +import com.p_vacho.neat_calendar.api.models.InvitationResponse import com.p_vacho.neat_calendar.api.models.NotificationResponse import java.time.Duration import java.time.OffsetDateTime @@ -17,6 +17,7 @@ class NotificationAdapter( private val notifications: MutableList, private val onActionClick: (NotificationResponse, Action, Int) -> Unit, private val onNotificationClick: (NotificationResponse, Int) -> Unit, + private val getInvitationData: (NotificationResponse) -> InvitationResponse?, ) : RecyclerView.Adapter() { enum class Action { @@ -42,8 +43,6 @@ class NotificationAdapter( override fun onBindViewHolder(holder: NotificationViewHolder, position: Int) { val notification = notifications[position] - holder.message.text = notification.message - // Format and set the creation time val formattedTime = formatNotificationTime(notification.created_at) holder.notificationTime.text = formattedTime @@ -53,17 +52,46 @@ class NotificationAdapter( // Handle invitation actions if (notification.event_type == "invitation") { - holder.invitationActions.visibility = View.VISIBLE - holder.acceptButton.setOnClickListener { - onActionClick(notification, Action.ACCEPT, position) - } - holder.declineButton.setOnClickListener { - onActionClick(notification, Action.DECLINE, position) - } - holder.viewEventButton.setOnClickListener { - onActionClick(notification, Action.VIEW_EVENT, position) + val invitation = getInvitationData(notification) + + // TODO: Consider fetching the user names here to show + // TODO: Localize + if (invitation != null) { + if (notification.message == "new-invitation") { + holder.message.setText("You have received an event invitation") + } else if (notification.message == "invitation-accepted") { + holder.message.setText("Your event invitation has been accepted") + } else if (notification.message == "invitation-declined") { + holder.message.setText("Your event invitation has been declined") + } + + holder.invitationActions.visibility = View.VISIBLE + + holder.acceptButton.setOnClickListener { + onActionClick(notification, Action.ACCEPT, position) + } + holder.declineButton.setOnClickListener { + onActionClick(notification, Action.DECLINE, position) + } + holder.viewEventButton.setOnClickListener { + onActionClick(notification, Action.VIEW_EVENT, position) + } + + } else { + if (notification.message == "new-invitation") { + holder.message.setText("You have received an event invitation [invitation deleted]") + } else if (notification.message == "invitation-accepted") { + holder.message.setText("Your event invitation has been accepted [invitation deleted]") + } else if (notification.message == "invitation-declined") { + holder.message.setText("Your event invitation has been declined [invitation deleted]") + } + + holder.invitationActions.visibility = View.GONE } + } else { + holder.message.text = notification.message + holder.invitationActions.visibility = View.GONE } diff --git a/app/src/main/java/com/p_vacho/neat_calendar/api/models/InvitationModels.kt b/app/src/main/java/com/p_vacho/neat_calendar/api/models/InvitationModels.kt index 9ae188b..3d42190 100644 --- a/app/src/main/java/com/p_vacho/neat_calendar/api/models/InvitationModels.kt +++ b/app/src/main/java/com/p_vacho/neat_calendar/api/models/InvitationModels.kt @@ -1,6 +1,18 @@ package com.p_vacho.neat_calendar.api.models +import java.time.OffsetDateTime + data class InvitationRequest( val event_id: String, val invitee_id: String, +) + +data class InvitationResponse( + val id: String, + val invitor_id: String, + val invitee_id: String, + val event_id: String, + val status: String, // "accepted" / "declined" / "pending" + val sent_at: OffsetDateTime, + val responded_at: OffsetDateTime?, ) \ No newline at end of file diff --git a/app/src/main/java/com/p_vacho/neat_calendar/api/services/InvitationsService.kt b/app/src/main/java/com/p_vacho/neat_calendar/api/services/InvitationsService.kt index b80d252..03c6f5f 100644 --- a/app/src/main/java/com/p_vacho/neat_calendar/api/services/InvitationsService.kt +++ b/app/src/main/java/com/p_vacho/neat_calendar/api/services/InvitationsService.kt @@ -1,10 +1,29 @@ package com.p_vacho.neat_calendar.api.services import com.p_vacho.neat_calendar.api.models.InvitationRequest +import com.p_vacho.neat_calendar.api.models.InvitationResponse import retrofit2.http.Body +import retrofit2.http.GET import retrofit2.http.POST +import retrofit2.http.Path interface InvitationsService { @POST("invitations") - suspend fun createInvitation(@Body invitationData: InvitationRequest) + suspend fun createInvitation(@Body invitationData: InvitationRequest): InvitationResponse + + @GET("invitations/{invitation_id}") + suspend fun getInvitation(@Path("invitation_id") invitiationId: String): InvitationResponse + + @GET("users/{user_id}/invitations") + suspend fun getInvitations(@Path("user_id") userId: String): List + + @GET("users/{user_id}/invitations/incoming") + suspend fun getIncomingInvitations(@Path("user_id") userId: String): List + + @POST("invitations/{invitation_id}/accept") + suspend fun acceptInvitation(@Path("invitation_id") invitationId: String): Unit + + @POST("invitations/{invitation_id}/decline") + suspend fun declineInvitation(@Path("invitation_id") invitationId: String): Unit + } \ No newline at end of file