notificaciones
This commit is contained in:
parent
bd994a17e8
commit
9667eafa49
@ -1,10 +1,15 @@
|
|||||||
package com.isolaatti.notifications.data
|
package com.isolaatti.notifications.data
|
||||||
|
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
|
import retrofit2.http.Body
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.POST
|
||||||
import retrofit2.http.Query
|
import retrofit2.http.Query
|
||||||
|
|
||||||
interface NotificationsApi {
|
interface NotificationsApi {
|
||||||
@GET("/api/Notifications/list")
|
@GET("/api/Notifications/list")
|
||||||
fun getNotifications(@Query("after") after: Long?): Call<NotificationsDto>
|
fun getNotifications(@Query("after") after: Long?): Call<NotificationsDto>
|
||||||
|
|
||||||
|
@POST("/api/Notifications/delete_many")
|
||||||
|
fun deleteNotifications(@Body ids: DeleteNotificationsDto): Call<Unit>
|
||||||
}
|
}
|
||||||
@ -1,6 +1,5 @@
|
|||||||
package com.isolaatti.notifications.data
|
package com.isolaatti.notifications.data
|
||||||
|
|
||||||
import com.google.gson.internal.LinkedTreeMap
|
|
||||||
import java.time.ZonedDateTime
|
import java.time.ZonedDateTime
|
||||||
|
|
||||||
data class NotificationsDto(
|
data class NotificationsDto(
|
||||||
@ -12,13 +11,7 @@ data class NotificationDto(
|
|||||||
val date: ZonedDateTime,
|
val date: ZonedDateTime,
|
||||||
val userId: Int,
|
val userId: Int,
|
||||||
val read: Boolean,
|
val read: Boolean,
|
||||||
val payload: NotificationPayload
|
|
||||||
)
|
|
||||||
|
|
||||||
data class NotificationPayload(
|
|
||||||
val type: String,
|
|
||||||
val authorId: Int,
|
|
||||||
val authorName: String?,
|
|
||||||
val intentData: String?,
|
|
||||||
val data: Map<String, String>
|
val data: Map<String, String>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data class DeleteNotificationsDto(val ids: List<Long>)
|
||||||
@ -14,10 +14,11 @@ class NotificationsRepositoryImpl(private val notificationsApi: NotificationsApi
|
|||||||
}
|
}
|
||||||
override fun getNotifications(after: Long?): Flow<Resource<List<Notification>>> = flow {
|
override fun getNotifications(after: Long?): Flow<Resource<List<Notification>>> = flow {
|
||||||
try {
|
try {
|
||||||
|
emit(Resource.Loading())
|
||||||
val response = notificationsApi.getNotifications(after).awaitResponse()
|
val response = notificationsApi.getNotifications(after).awaitResponse()
|
||||||
|
|
||||||
if(response.isSuccessful) {
|
if(response.isSuccessful) {
|
||||||
|
emit(Resource.Success(response.body()!!.result.mapNotNull { Notification.fromDto(it) }))
|
||||||
} else {
|
} else {
|
||||||
Log.e(LOG_TAG, "getNotifications(): Request is not successful, response code is ${response.code()}")
|
Log.e(LOG_TAG, "getNotifications(): Request is not successful, response code is ${response.code()}")
|
||||||
emit(Resource.Error(Resource.Error.mapErrorCode(response.code())))
|
emit(Resource.Error(Resource.Error.mapErrorCode(response.code())))
|
||||||
@ -27,4 +28,21 @@ class NotificationsRepositoryImpl(private val notificationsApi: NotificationsApi
|
|||||||
emit(Resource.Error(Resource.Error.ErrorType.OtherError))
|
emit(Resource.Error(Resource.Error.ErrorType.OtherError))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun deleteNotifications(vararg notification: Notification): Flow<Resource<Boolean>> = flow {
|
||||||
|
try {
|
||||||
|
emit(Resource.Loading())
|
||||||
|
val response = notificationsApi.deleteNotifications(DeleteNotificationsDto(notification.map { it.id })).awaitResponse()
|
||||||
|
|
||||||
|
if(response.isSuccessful) {
|
||||||
|
emit(Resource.Success(true))
|
||||||
|
} else {
|
||||||
|
Log.e(LOG_TAG, "deleteNotifications(): Request is not successful, response code is ${response.code()}")
|
||||||
|
emit(Resource.Error(Resource.Error.mapErrorCode(response.code())))
|
||||||
|
}
|
||||||
|
} catch(e: Exception) {
|
||||||
|
Log.e(LOG_TAG, e.message.toString())
|
||||||
|
emit(Resource.Error(Resource.Error.ErrorType.OtherError))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,8 +1,6 @@
|
|||||||
package com.isolaatti.notifications.domain
|
package com.isolaatti.notifications.domain
|
||||||
|
|
||||||
import com.isolaatti.databinding.NotificationItemBinding
|
|
||||||
import com.isolaatti.notifications.data.NotificationDto
|
import com.isolaatti.notifications.data.NotificationDto
|
||||||
import com.isolaatti.notifications.data.NotificationPayload
|
|
||||||
import java.time.ZonedDateTime
|
import java.time.ZonedDateTime
|
||||||
|
|
||||||
|
|
||||||
@ -11,14 +9,29 @@ class GenericNotification(id: Long, date: ZonedDateTime, userId: Int, read: Bool
|
|||||||
var title: String? = null
|
var title: String? = null
|
||||||
var message: String? = null
|
var message: String? = null
|
||||||
|
|
||||||
override fun ingestPayload(notificationPayload: NotificationPayload) {
|
override fun ingestPayload(data: Map<String, String>) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bind(notificationBinding: NotificationItemBinding) {
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as GenericNotification
|
||||||
|
|
||||||
|
if (title != other.title) return false
|
||||||
|
if (message != other.message) return false
|
||||||
|
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = title?.hashCode() ?: 0
|
||||||
|
result = 31 * result + (message?.hashCode() ?: 0)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val TYPE = "generic"
|
const val TYPE = "generic"
|
||||||
}
|
}
|
||||||
@ -29,13 +42,39 @@ class LikeNotification(id: Long, date: ZonedDateTime, userId: Int, read: Boolean
|
|||||||
const val TYPE = "like"
|
const val TYPE = "like"
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun ingestPayload(notificationPayload: NotificationPayload) {
|
var likeId: String? = null
|
||||||
TODO("Not yet implemented")
|
var postId: Long? = null
|
||||||
|
var authorId: Int? = null
|
||||||
|
var authorName: String? = null
|
||||||
|
override fun ingestPayload(data: Map<String, String>) {
|
||||||
|
likeId = data["likeId"]
|
||||||
|
postId = data["postId"]?.toLongOrNull()
|
||||||
|
authorId = data["authorId"]?.toIntOrNull()
|
||||||
|
authorName = data["authorName"]
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bind(notificationBinding: NotificationItemBinding) {
|
override fun equals(other: Any?): Boolean {
|
||||||
TODO("Not yet implemented")
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as LikeNotification
|
||||||
|
|
||||||
|
if (likeId != other.likeId) return false
|
||||||
|
if (postId != other.postId) return false
|
||||||
|
if (authorId != other.authorId) return false
|
||||||
|
if (authorName != other.authorName) return false
|
||||||
|
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = likeId?.hashCode() ?: 0
|
||||||
|
result = 31 * result + (postId?.hashCode() ?: 0)
|
||||||
|
result = 31 * result + (authorId ?: 0)
|
||||||
|
result = 31 * result + (authorName?.hashCode() ?: 0)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class FollowNotification(id: Long, date: ZonedDateTime, userId: Int, read: Boolean) : Notification(id, date, userId, read) {
|
class FollowNotification(id: Long, date: ZonedDateTime, userId: Int, read: Boolean) : Notification(id, date, userId, read) {
|
||||||
@ -44,12 +83,30 @@ class FollowNotification(id: Long, date: ZonedDateTime, userId: Int, read: Boole
|
|||||||
const val TYPE = "follower"
|
const val TYPE = "follower"
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun ingestPayload(notificationPayload: NotificationPayload) {
|
var followerName: String? = null
|
||||||
TODO("Not yet implemented")
|
var followerUserId: Int? = null
|
||||||
|
|
||||||
|
override fun ingestPayload(data: Map<String, String>) {
|
||||||
|
followerName = data["followerName"]
|
||||||
|
followerUserId = data["followerUserId"]?.toIntOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bind(notificationBinding: NotificationItemBinding) {
|
override fun equals(other: Any?): Boolean {
|
||||||
TODO("Not yet implemented")
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as FollowNotification
|
||||||
|
|
||||||
|
if (followerName != other.followerName) return false
|
||||||
|
if (followerUserId != other.followerUserId) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = followerName?.hashCode() ?: 0
|
||||||
|
result = 31 * result + (followerUserId ?: 0)
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,13 +118,31 @@ abstract class Notification(
|
|||||||
var read: Boolean
|
var read: Boolean
|
||||||
) {
|
) {
|
||||||
|
|
||||||
abstract fun ingestPayload(notificationPayload: NotificationPayload)
|
abstract fun ingestPayload(data: Map<String, String>)
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (other !is Notification) return false
|
||||||
|
|
||||||
abstract fun bind(notificationBinding: NotificationItemBinding)
|
if (id != other.id) return false
|
||||||
|
if (date != other.date) return false
|
||||||
|
if (userId != other.userId) return false
|
||||||
|
if (read != other.read) return false
|
||||||
|
if (other != this) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = id.hashCode()
|
||||||
|
result = 31 * result + date.hashCode()
|
||||||
|
result = 31 * result + userId
|
||||||
|
result = 31 * result + read.hashCode()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun fromDto(notificationDto: NotificationDto): Notification? {
|
fun fromDto(notificationDto: NotificationDto): Notification? {
|
||||||
return when(notificationDto.payload.type) {
|
val type = notificationDto.data["type"]
|
||||||
|
return when(type) {
|
||||||
GenericNotification.TYPE -> {
|
GenericNotification.TYPE -> {
|
||||||
|
|
||||||
GenericNotification(
|
GenericNotification(
|
||||||
@ -76,7 +151,7 @@ abstract class Notification(
|
|||||||
notificationDto.userId,
|
notificationDto.userId,
|
||||||
notificationDto.read
|
notificationDto.read
|
||||||
).apply {
|
).apply {
|
||||||
ingestPayload(notificationDto.payload)
|
ingestPayload(notificationDto.data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LikeNotification.TYPE -> {
|
LikeNotification.TYPE -> {
|
||||||
@ -86,7 +161,7 @@ abstract class Notification(
|
|||||||
notificationDto.userId,
|
notificationDto.userId,
|
||||||
notificationDto.read
|
notificationDto.read
|
||||||
).apply {
|
).apply {
|
||||||
ingestPayload(notificationDto.payload)
|
ingestPayload(notificationDto.data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FollowNotification.TYPE -> {
|
FollowNotification.TYPE -> {
|
||||||
@ -96,7 +171,7 @@ abstract class Notification(
|
|||||||
notificationDto.userId,
|
notificationDto.userId,
|
||||||
notificationDto.read
|
notificationDto.read
|
||||||
).apply {
|
).apply {
|
||||||
ingestPayload(notificationDto.payload)
|
ingestPayload(notificationDto.data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> null
|
else -> null
|
||||||
|
|||||||
@ -5,4 +5,5 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
|
|
||||||
interface NotificationsRepository {
|
interface NotificationsRepository {
|
||||||
fun getNotifications(after: Long?): Flow<Resource<List<Notification>>>
|
fun getNotifications(after: Long?): Flow<Resource<List<Notification>>>
|
||||||
|
fun deleteNotifications(vararg notification: Notification): Flow<Resource<Boolean>>
|
||||||
}
|
}
|
||||||
@ -1,16 +1,23 @@
|
|||||||
package com.isolaatti.notifications.presentation
|
package com.isolaatti.notifications.presentation
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||||
|
import coil.load
|
||||||
|
import com.isolaatti.R
|
||||||
import com.isolaatti.databinding.NotificationItemBinding
|
import com.isolaatti.databinding.NotificationItemBinding
|
||||||
|
import com.isolaatti.notifications.domain.FollowNotification
|
||||||
|
import com.isolaatti.notifications.domain.LikeNotification
|
||||||
import com.isolaatti.notifications.domain.Notification
|
import com.isolaatti.notifications.domain.Notification
|
||||||
|
import com.isolaatti.utils.UrlGen
|
||||||
|
|
||||||
class NotificationsAdapter : ListAdapter<Notification, NotificationsAdapter.NotificationViewHolder>(
|
class NotificationsAdapter(
|
||||||
diffCallback
|
private val onNotificationClick: (notification: Notification) -> Unit,
|
||||||
) {
|
private val onItemOptionsClick: (button: View, notification: Notification) -> Unit
|
||||||
|
) : ListAdapter<Notification, NotificationsAdapter.NotificationViewHolder>(diffCallback) {
|
||||||
inner class NotificationViewHolder(val notificationItemBinding: NotificationItemBinding) : ViewHolder(notificationItemBinding.root)
|
inner class NotificationViewHolder(val notificationItemBinding: NotificationItemBinding) : ViewHolder(notificationItemBinding.root)
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NotificationViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NotificationViewHolder {
|
||||||
@ -18,19 +25,61 @@ class NotificationsAdapter : ListAdapter<Notification, NotificationsAdapter.Noti
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: NotificationViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: NotificationViewHolder, position: Int) {
|
||||||
getItem(position).bind(holder.notificationItemBinding)
|
val context = holder.notificationItemBinding.root.context
|
||||||
|
val notification = getItem(position)
|
||||||
|
holder.notificationItemBinding.root.setOnClickListener {
|
||||||
|
onNotificationClick(notification)
|
||||||
|
}
|
||||||
|
holder.notificationItemBinding.optionButton.setOnClickListener {
|
||||||
|
onItemOptionsClick(it, notification)
|
||||||
|
}
|
||||||
|
when(notification) {
|
||||||
|
is LikeNotification -> {
|
||||||
|
holder.notificationItemBinding.notificationTitle.text = context.getString(R.string.like_notification_title, notification.authorName)
|
||||||
|
holder.notificationItemBinding.notificationMessage.text = context.getString(R.string.like_notification_text)
|
||||||
|
val authorProfileImageUrl = notification.authorId?.let { UrlGen.userProfileImage(it, false) }
|
||||||
|
|
||||||
|
if(authorProfileImageUrl != null) {
|
||||||
|
holder.notificationItemBinding.notificationMainImage.load(authorProfileImageUrl){
|
||||||
|
fallback(R.drawable.baseline_person_24)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
holder.notificationItemBinding.notificationMainImage.load(R.drawable.baseline_person_24)
|
||||||
|
}
|
||||||
|
|
||||||
|
holder.notificationItemBinding.notificationSecondaryImage.load(R.drawable.hands_clapping_solid)
|
||||||
|
}
|
||||||
|
|
||||||
|
is FollowNotification -> {
|
||||||
|
holder.notificationItemBinding.notificationTitle.text = context.getString(R.string.new_follower_notification_title, notification.followerName)
|
||||||
|
holder.notificationItemBinding.notificationMessage.text = context.getString(R.string.new_follower_notification_text)
|
||||||
|
|
||||||
|
val followerProfileImageUrl = notification.followerUserId?.let { UrlGen.userProfileImage(it, false) }
|
||||||
|
if(followerProfileImageUrl != null) {
|
||||||
|
holder.notificationItemBinding.notificationMainImage.load(followerProfileImageUrl) {
|
||||||
|
fallback(R.drawable.baseline_person_24)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
holder.notificationItemBinding.notificationMainImage.load(R.drawable.baseline_person_24)
|
||||||
|
}
|
||||||
|
|
||||||
|
holder.notificationItemBinding.notificationSecondaryImage.load(R.drawable.baseline_star_24)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val diffCallback = object: DiffUtil.ItemCallback<Notification>() {
|
val diffCallback = object: DiffUtil.ItemCallback<Notification>() {
|
||||||
override fun areItemsTheSame(oldItem: Notification, newItem: Notification): Boolean {
|
override fun areItemsTheSame(oldItem: Notification, newItem: Notification): Boolean {
|
||||||
TODO("Not yet implemented")
|
return oldItem.id == newItem.id
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun areContentsTheSame(oldItem: Notification, newItem: Notification): Boolean {
|
override fun areContentsTheSame(oldItem: Notification, newItem: Notification): Boolean {
|
||||||
TODO("Not yet implemented")
|
return oldItem == newItem
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,11 +1,71 @@
|
|||||||
package com.isolaatti.notifications.presentation
|
package com.isolaatti.notifications.presentation
|
||||||
|
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.isolaatti.notifications.domain.Notification
|
||||||
import com.isolaatti.notifications.domain.NotificationsRepository
|
import com.isolaatti.notifications.domain.NotificationsRepository
|
||||||
|
import com.isolaatti.utils.Resource
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.flowOn
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class NotificationsViewModel @Inject constructor(private val notificationsRepository: NotificationsRepository) : ViewModel() {
|
class NotificationsViewModel @Inject constructor(private val notificationsRepository: NotificationsRepository) : ViewModel() {
|
||||||
|
companion object {
|
||||||
|
const val LOG_TAG = "NotificationsViewModel"
|
||||||
|
}
|
||||||
|
val notifications: MutableLiveData<List<Notification>> = MutableLiveData()
|
||||||
|
val loading: MutableLiveData<Boolean> = MutableLiveData()
|
||||||
|
|
||||||
|
val error: MutableLiveData<Boolean> = MutableLiveData()
|
||||||
|
fun getData() {
|
||||||
|
viewModelScope.launch {
|
||||||
|
notificationsRepository.getNotifications(null).onEach {
|
||||||
|
when(it) {
|
||||||
|
is Resource.Error -> {
|
||||||
|
loading.postValue(false)
|
||||||
|
}
|
||||||
|
is Resource.Loading -> {
|
||||||
|
loading.postValue(true)
|
||||||
|
}
|
||||||
|
is Resource.Success -> {
|
||||||
|
loading.postValue(false)
|
||||||
|
notifications.postValue(it.data!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.flowOn(Dispatchers.IO).launchIn(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onDeleted(notification: Notification) {
|
||||||
|
val mutableList = notifications.value?.toMutableList()
|
||||||
|
val removed = mutableList?.remove(notification)
|
||||||
|
if(mutableList != null && removed == true) {
|
||||||
|
notifications.postValue(mutableList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteNotification(notification: Notification) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
notificationsRepository.deleteNotifications(notification).onEach {
|
||||||
|
when(it) {
|
||||||
|
is Resource.Error -> {
|
||||||
|
error.postValue(true)
|
||||||
|
}
|
||||||
|
is Resource.Loading -> {
|
||||||
|
error.postValue(false)
|
||||||
|
}
|
||||||
|
is Resource.Success -> {
|
||||||
|
error.postValue(false)
|
||||||
|
onDeleted(notification)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.flowOn(Dispatchers.IO).launchIn(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,33 +1,125 @@
|
|||||||
package com.isolaatti.notifications.ui
|
package com.isolaatti.notifications.ui
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.appcompat.widget.PopupMenu
|
||||||
|
import androidx.fragment.app.viewModels
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.isolaatti.R
|
import com.isolaatti.R
|
||||||
|
import com.isolaatti.databinding.FragmentNotificationsBinding
|
||||||
|
import com.isolaatti.notifications.domain.FollowNotification
|
||||||
|
import com.isolaatti.notifications.domain.LikeNotification
|
||||||
|
import com.isolaatti.notifications.domain.Notification
|
||||||
|
import com.isolaatti.notifications.presentation.NotificationsAdapter
|
||||||
import com.isolaatti.notifications.presentation.NotificationsViewModel
|
import com.isolaatti.notifications.presentation.NotificationsViewModel
|
||||||
|
import com.isolaatti.posting.posts.viewer.ui.PostViewerActivity
|
||||||
|
import com.isolaatti.profile.ui.ProfileActivity
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
class NotificationsFragment : Fragment() {
|
class NotificationsFragment : Fragment() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun newInstance() = NotificationsFragment()
|
fun newInstance() = NotificationsFragment()
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var viewModel: NotificationsViewModel
|
private lateinit var binding: FragmentNotificationsBinding
|
||||||
|
private val viewModel: NotificationsViewModel by viewModels()
|
||||||
|
private var adapter: NotificationsAdapter? = null
|
||||||
|
|
||||||
|
private fun showDeleteNotificationDialog(notification: Notification) {
|
||||||
|
MaterialAlertDialogBuilder(requireContext())
|
||||||
|
.setTitle(R.string.delete_notification)
|
||||||
|
.setMessage(R.string.delete_notification_dialog_message)
|
||||||
|
.setPositiveButton(R.string.accept) { _, _ ->
|
||||||
|
viewModel.deleteNotification(notification)
|
||||||
|
}
|
||||||
|
.setNegativeButton(R.string.no, null)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val onItemOptionsClick: (button: View, notification: Notification) -> Unit = { button, notification ->
|
||||||
|
val popupMenu = PopupMenu(requireContext(), button)
|
||||||
|
|
||||||
|
popupMenu.inflate(R.menu.notification_menu)
|
||||||
|
|
||||||
|
popupMenu.setOnMenuItemClickListener {
|
||||||
|
when(it.itemId) {
|
||||||
|
R.id.delete_notification -> {
|
||||||
|
showDeleteNotificationDialog(notification)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
popupMenu.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val onNotificationClick: (notification: Notification) -> Unit = { notification ->
|
||||||
|
when(notification) {
|
||||||
|
is LikeNotification -> {
|
||||||
|
notification.postId?.also { postId ->
|
||||||
|
PostViewerActivity.startActivity(requireContext(), postId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is FollowNotification -> {
|
||||||
|
notification.followerUserId?.also { followerUserId ->
|
||||||
|
ProfileActivity.startActivity(requireContext(), followerUserId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View? {
|
): View? {
|
||||||
return inflater.inflate(R.layout.fragment_notifications, container, false)
|
binding = FragmentNotificationsBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
viewModel = ViewModelProvider(this).get(NotificationsViewModel::class.java)
|
|
||||||
// TODO: Use the ViewModel
|
|
||||||
|
adapter = NotificationsAdapter(onNotificationClick, onItemOptionsClick)
|
||||||
|
binding.recycler.adapter = adapter
|
||||||
|
binding.recycler.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
|
||||||
|
|
||||||
|
viewModel.getData()
|
||||||
|
|
||||||
|
setupObservers()
|
||||||
|
setupListeners()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setupListeners() {
|
||||||
|
binding.swipeToRefresh.setOnRefreshListener {
|
||||||
|
viewModel.getData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupObservers() {
|
||||||
|
viewModel.notifications.observe(viewLifecycleOwner) {
|
||||||
|
adapter?.submitList(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.loading.observe(viewLifecycleOwner) {
|
||||||
|
binding.swipeToRefresh.isRefreshing = it
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.error.observe(viewLifecycleOwner) {
|
||||||
|
if(it){
|
||||||
|
Toast.makeText(requireContext(), R.string.error_making_request, Toast.LENGTH_SHORT).show()
|
||||||
|
viewModel.error.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user