-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
[FEAT/#133] 알림 화면 연결
- Loading branch information
Showing
23 changed files
with
488 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
108 changes: 108 additions & 0 deletions
108
app/src/main/java/com/teumteum/teumteum/presentation/notification/AlertsListActivity.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package com.teumteum.teumteum.presentation.notification | ||
|
||
import android.os.Bundle | ||
import androidx.activity.viewModels | ||
import androidx.core.view.isVisible | ||
import androidx.lifecycle.flowWithLifecycle | ||
import androidx.lifecycle.lifecycleScope | ||
import com.teumteum.base.BindingActivity | ||
import com.teumteum.base.component.appbar.AppBarLayout | ||
import com.teumteum.base.component.appbar.AppBarMenu | ||
import com.teumteum.base.databinding.LayoutCommonAppbarBinding | ||
import com.teumteum.base.util.extension.defaultToast | ||
import com.teumteum.domain.entity.TeumAlert | ||
import com.teumteum.teumteum.R | ||
import com.teumteum.teumteum.databinding.ActivityAlertsListBinding | ||
import com.teumteum.teumteum.presentation.group.GroupListUiState | ||
import dagger.hilt.android.AndroidEntryPoint | ||
import kotlinx.coroutines.flow.launchIn | ||
import kotlinx.coroutines.flow.onEach | ||
|
||
@AndroidEntryPoint | ||
class AlertsListActivity | ||
: BindingActivity<ActivityAlertsListBinding>(R.layout.activity_alerts_list), AppBarLayout { | ||
|
||
private lateinit var adapter: AlertsListAdapter | ||
private val viewModel by viewModels<AlertsViewModel>() | ||
|
||
override fun onCreate(savedInstanceState: Bundle?) { | ||
super.onCreate(savedInstanceState) | ||
|
||
initAppBarLayout() | ||
initList() | ||
viewModel.getAlerts() | ||
observe() | ||
} | ||
|
||
override val appBarBinding: LayoutCommonAppbarBinding | ||
get() = binding.appBar | ||
|
||
override fun initAppBarLayout() { | ||
setAppBarHeight(48) | ||
|
||
addMenuToLeft( | ||
AppBarMenu.IconStyle( | ||
resourceId = R.drawable.ic_arrow_left_l, | ||
useRippleEffect = false, | ||
clickEvent = ::finish | ||
) | ||
) | ||
setAppBarTitleText(R.string.alerts_list_title) | ||
} | ||
|
||
private fun initItems() { | ||
adapter.setItems(listOf( | ||
TeumAlert("틈 채우기", "한별님이 당신을 추천했어요!", RECOMMEND_USER, "2024-01-30T16:33:00", false), | ||
TeumAlert("틈 채우기", "한별님이 당신을 추천했어요!", RECOMMEND_USER, "2024-01-31T16:33:00", false), | ||
TeumAlert("틈 채우기", "한별님이 당신을 추천했어요!", RECOMMEND_USER, "2024-02-10T16:33:00", false), | ||
TeumAlert("틈 채우기", "한별님이 당신을 추천했어요!", RECOMMEND_USER, "2024-02-11T16:33:00", false), | ||
TeumAlert("틈 채우기", "한별님이 당신을 추천했어요!", RECOMMEND_USER, "2024-02-12T09:33:00", false), | ||
TeumAlert("틈 채우기", "한별님이 당신을 추천했어요!", RECOMMEND_USER, "2024-02-12T10:33:00", false) | ||
)) | ||
} | ||
|
||
private fun observe() { | ||
viewModel.alertsData.flowWithLifecycle(lifecycle) | ||
.onEach { | ||
binding.clEmpty.isVisible = it is AlertsListUiState.Empty | ||
binding.tvNoticeEmpty.isVisible = it !is AlertsListUiState.Empty | ||
binding.rvAlertsList.isVisible = it !is AlertsListUiState.Empty | ||
when (it) { | ||
is AlertsListUiState.SetAlerts -> { | ||
adapter.setItems(it.data) | ||
} | ||
is AlertsListUiState.Failure -> { | ||
defaultToast(it.msg) | ||
} | ||
else -> {} | ||
} | ||
}.launchIn(lifecycleScope) | ||
} | ||
|
||
private fun initList() { | ||
adapter = AlertsListAdapter { | ||
when (it.type) { | ||
// 알림 리스트에서 클릭 시 이동하는 정책이 있다면 | ||
BEFORE_MEETING -> { | ||
// 틈틈으로 이동 | ||
// openActivitySlideAnimation() | ||
} | ||
END_MEETING -> { | ||
// 해당 모임 종료 화면으로 이동 | ||
// openActivitySlideAnimation() | ||
} | ||
RECOMMEND_USER -> { | ||
// 마이페이지로 이동 | ||
// openActivitySlideAnimation() | ||
} | ||
} | ||
} | ||
binding.rvAlertsList.adapter = adapter | ||
} | ||
|
||
companion object { | ||
private const val BEFORE_MEETING = "BEFORE_MEETING" | ||
private const val END_MEETING = "END_MEETING" | ||
private const val RECOMMEND_USER = "RECOMMEND_USER" | ||
} | ||
} |
80 changes: 80 additions & 0 deletions
80
app/src/main/java/com/teumteum/teumteum/presentation/notification/AlertsListAdapter.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package com.teumteum.teumteum.presentation.notification | ||
|
||
import android.content.Context | ||
import android.view.LayoutInflater | ||
import android.view.ViewGroup | ||
import androidx.recyclerview.widget.RecyclerView | ||
import com.teumteum.base.R.* | ||
import com.teumteum.base.util.extension.setOnSingleClickListener | ||
import com.teumteum.domain.entity.TeumAlert | ||
import com.teumteum.teumteum.databinding.ItemAlertsListBinding | ||
import java.time.LocalDateTime | ||
import java.time.format.DateTimeFormatter | ||
|
||
class AlertsListAdapter(private val itemClick: (TeumAlert) -> (Unit)) : | ||
RecyclerView.Adapter<AlertsListAdapter.AlertsListViewHolder>() { | ||
private val alertList = mutableListOf<TeumAlert>() | ||
|
||
override fun onCreateViewHolder( | ||
parent: ViewGroup, | ||
viewType: Int | ||
): AlertsListViewHolder { | ||
val binding = ItemAlertsListBinding.inflate( | ||
LayoutInflater.from(parent.context), | ||
parent, | ||
false | ||
) | ||
return AlertsListViewHolder(binding, parent.context, itemClick) | ||
} | ||
|
||
override fun onBindViewHolder(holder: AlertsListViewHolder, position: Int) { | ||
holder.onBind(alertList[position]) | ||
} | ||
|
||
override fun getItemCount(): Int = alertList.size | ||
|
||
fun setItems(newItems: List<TeumAlert>) { | ||
alertList.clear() | ||
alertList.addAll(newItems.sortedByDescending { | ||
LocalDateTime.parse(it.createdAt, DateTimeFormatter.ISO_LOCAL_DATE_TIME) | ||
}) | ||
notifyDataSetChanged() | ||
} | ||
|
||
class AlertsListViewHolder( | ||
private val binding: ItemAlertsListBinding, | ||
private val context: Context, | ||
private val itemClick: (TeumAlert) -> (Unit) | ||
) : RecyclerView.ViewHolder(binding.root) { | ||
|
||
fun onBind(item: TeumAlert) { | ||
binding.tvTitle.text = item.title | ||
binding.tvContent.text = item.body | ||
binding.tvTime.text = getTimeDifference(item.createdAt) | ||
|
||
if (!item.isRead) { | ||
binding.root.setBackgroundColor(context.getColor(color.elevation_level01)) | ||
} else { | ||
binding.root.setBackgroundColor(context.getColor(color.transparent)) | ||
} | ||
binding.root.setOnSingleClickListener { | ||
itemClick(item) | ||
} | ||
} | ||
|
||
private fun getTimeDifference(inputDateTime: String): String { | ||
val currentTime = LocalDateTime.now() | ||
val formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME | ||
val inputTime = LocalDateTime.parse(inputDateTime, formatter) | ||
|
||
val diffInMinutes = java.time.Duration.between(inputTime, currentTime).toMinutes() | ||
val diffInHours = java.time.Duration.between(inputTime, currentTime).toHours() | ||
|
||
return when { | ||
diffInMinutes < 60 -> "${diffInMinutes}분 전" | ||
diffInHours < 24 -> "${diffInHours}시간 전" | ||
else -> "${inputTime.monthValue}월 ${inputTime.dayOfMonth}일" | ||
} | ||
} | ||
} | ||
} |
40 changes: 40 additions & 0 deletions
40
app/src/main/java/com/teumteum/teumteum/presentation/notification/AlertsViewModel.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package com.teumteum.teumteum.presentation.notification | ||
|
||
import androidx.lifecycle.ViewModel | ||
import androidx.lifecycle.viewModelScope | ||
import com.teumteum.domain.entity.TeumAlert | ||
import com.teumteum.domain.repository.UserRepository | ||
import dagger.hilt.android.lifecycle.HiltViewModel | ||
import kotlinx.coroutines.flow.MutableStateFlow | ||
import kotlinx.coroutines.flow.StateFlow | ||
import kotlinx.coroutines.launch | ||
import javax.inject.Inject | ||
|
||
@HiltViewModel | ||
class AlertsViewModel @Inject constructor( | ||
private val repository: UserRepository | ||
) : ViewModel() { | ||
|
||
private val _alertsData = MutableStateFlow<AlertsListUiState>(AlertsListUiState.Init) | ||
val alertsData: StateFlow<AlertsListUiState> = _alertsData | ||
|
||
fun getAlerts() { | ||
viewModelScope.launch { | ||
repository.getAlerts() | ||
.onSuccess { | ||
if (it.alerts.isEmpty()) _alertsData.value = AlertsListUiState.Empty | ||
else _alertsData.value = AlertsListUiState.SetAlerts(it.alerts) | ||
} | ||
.onFailure { | ||
_alertsData.value = AlertsListUiState.Failure("알림 가져오기 실패") | ||
} | ||
} | ||
} | ||
} | ||
|
||
sealed interface AlertsListUiState { | ||
object Init : AlertsListUiState | ||
object Empty : AlertsListUiState | ||
data class SetAlerts(val data: List<TeumAlert>) : AlertsListUiState | ||
data class Failure(val msg: String) : AlertsListUiState | ||
} |
Oops, something went wrong.