refactor #1620: migrated notification screen to compose

This commit is contained in:
Pratyush Singh 2024-05-06 23:48:58 +05:30 committed by Rajan Maurya
parent 3e0e3e9d84
commit 9652b268ae
4 changed files with 231 additions and 67 deletions

View File

@ -17,7 +17,7 @@ class FetchNotifications @Inject constructor(private val mFineractRepository: Fi
class RequestValues(val clientId: Long) : UseCase.RequestValues
class ResponseValue(
val notificationPayloadList: List<NotificationPayload?>
val notificationPayloadList: List<NotificationPayload>?
) : UseCase.ResponseValue
override fun executeUseCase(requestValues: RequestValues) {

View File

@ -0,0 +1,48 @@
package org.mifospay.notification.presenter
import androidx.lifecycle.ViewModel
import com.mifospay.core.model.domain.NotificationPayload
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import org.mifospay.core.data.base.UseCase
import org.mifospay.core.data.base.UseCaseHandler
import org.mifospay.core.data.domain.usecase.notification.FetchNotifications
import org.mifospay.data.local.LocalRepository
import javax.inject.Inject
@HiltViewModel
class NotificationViewModel @Inject constructor(
private val mUseCaseHandler: UseCaseHandler,
private val mLocalRepository: LocalRepository,
private val fetchNotificationsUseCase: FetchNotifications
) : ViewModel() {
private val _notificationUiState: MutableStateFlow<NotificationUiState> =
MutableStateFlow(NotificationUiState.Loading)
val notificationUiState: StateFlow<NotificationUiState> = _notificationUiState
fun fetchNotifications() {
mUseCaseHandler.execute(fetchNotificationsUseCase,
FetchNotifications.RequestValues(
mLocalRepository.clientDetails.clientId
),
object : UseCase.UseCaseCallback<FetchNotifications.ResponseValue> {
override fun onSuccess(response: FetchNotifications.ResponseValue) {
_notificationUiState.value =
NotificationUiState.Success(response.notificationPayloadList.orEmpty())
}
override fun onError(message: String) {
_notificationUiState.value = NotificationUiState.Error(message)
}
})
}
}
sealed interface NotificationUiState {
data object Loading : NotificationUiState
data object Empty : NotificationUiState
data class Success(val notificationList: List<NotificationPayload>) : NotificationUiState
data class Error(val message: String) : NotificationUiState
}

View File

@ -3,6 +3,7 @@ package org.mifospay.notification.ui
import android.os.Bundle
import android.view.View
import android.widget.TextView
import androidx.activity.compose.setContent
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
@ -16,6 +17,7 @@ import org.mifospay.notification.NotificationContract
import org.mifospay.notification.NotificationContract.NotificationView
import org.mifospay.notification.presenter.NotificationPresenter
import org.mifospay.common.Constants
import org.mifospay.theme.MifosTheme
import org.mifospay.utils.DebugUtil
import org.mifospay.utils.Toaster
import javax.inject.Inject
@ -26,77 +28,21 @@ import javax.inject.Inject
* This feature is yet to be implemented on the server side.
*/
@AndroidEntryPoint
class NotificationActivity : BaseActivity(), NotificationView {
@JvmField
@Inject
var mPresenter: NotificationPresenter? = null
var mNotificationPresenter: NotificationContract.NotificationPresenter? = null
class NotificationActivity : BaseActivity() {
@JvmField
@BindView(R.id.rv_notification)
var mRvNotification: RecyclerView? = null
@JvmField
@BindView(R.id.tv_placeholder)
var tvplaceholder: TextView? = null
@JvmField
@Inject
var mNotificationAdapter: NotificationAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_notification)
ButterKnife.bind(this)
setToolbarTitle("Notifications")
showColoredBackButton(R.drawable.ic_arrow_back_black_24dp)
setupRecyclerView()
setupSwipeRefreshLayout()
mPresenter?.attachView(this)
showSwipeProgress()
mNotificationPresenter?.fetchNotifications()
}
private fun setupRecyclerView() {
mRvNotification?.layoutManager = LinearLayoutManager(this)
mRvNotification?.adapter = mNotificationAdapter
mRvNotification?.addItemDecoration(
DividerItemDecoration(
this,
DividerItemDecoration.VERTICAL
)
)
}
private fun setupSwipeRefreshLayout() {
setSwipeRefreshEnabled(true)
swipeRefreshLayout?.setOnRefreshListener { mNotificationPresenter?.fetchNotifications() }
}
override fun fetchNotificationsSuccess(notificationPayloadList: List<NotificationPayload?>?) {
hideSwipeProgress()
if (notificationPayloadList.isNullOrEmpty()) {
DebugUtil.log("null")
mRvNotification?.visibility = View.GONE
tvplaceholder?.visibility = View.VISIBLE
} else {
DebugUtil.log("yes")
mRvNotification?.visibility = View.VISIBLE
tvplaceholder?.visibility = View.GONE
mNotificationAdapter?.setNotificationPayloadList(notificationPayloadList as List<NotificationPayload>)
setContent {
MifosTheme {
NotificationScreen()
}
}
mNotificationAdapter?.setNotificationPayloadList(notificationPayloadList as List<NotificationPayload>)
// mNotificationPresenter?.fetchNotifications()
}
override fun fetchNotificationsError(message: String?) {
hideSwipeProgress()
showToast(message)
}
// private fun setupSwipeRefreshLayout() {
// setSwipeRefreshEnabled(true)
// swipeRefreshLayout?.setOnRefreshListener { mNotificationPresenter?.fetchNotifications() }
// }
override fun setPresenter(presenter: NotificationContract.NotificationPresenter?) {
mNotificationPresenter = presenter
}
fun showToast(message: String?) {
Toaster.showToast(this, message)
}
}

View File

@ -0,0 +1,170 @@
package org.mifospay.notification.ui
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Info
import androidx.compose.material3.Card
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Text
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.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.mifospay.core.model.domain.NotificationPayload
import org.mifospay.R
import org.mifospay.core.designsystem.component.MfLoadingWheel
import org.mifospay.core.designsystem.component.MifosTopAppBar
import org.mifospay.core.designsystem.theme.historyItemTextStyle
import org.mifospay.core.designsystem.theme.styleMedium16sp
import org.mifospay.core.ui.EmptyContentScreen
import org.mifospay.notification.presenter.NotificationUiState
import org.mifospay.notification.presenter.NotificationViewModel
@Composable
fun NotificationScreen(viewmodel: NotificationViewModel = hiltViewModel()) {
val uiState by viewmodel.notificationUiState.collectAsStateWithLifecycle()
NotificationScreen(uiState = uiState)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun NotificationScreen(uiState: NotificationUiState) {
Column(
modifier = Modifier.fillMaxSize()
) {
MifosTopAppBar(titleRes = R.string.notifications)
when (uiState) {
is NotificationUiState.Error -> {
EmptyContentScreen(
modifier = Modifier,
title = stringResource(id = R.string.error_oops),
subTitle = stringResource(id = R.string.unexpected_error_subtitle),
iconTint = Color.Black,
iconImageVector = Icons.Rounded.Info
)
}
NotificationUiState.Loading -> {
MfLoadingWheel(
contentDesc = stringResource(R.string.loading),
backgroundColor = Color.White
)
}
is NotificationUiState.Success -> {
if (uiState.notificationList.isEmpty()) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = stringResource(id = R.string.no_notification_found),
style = styleMedium16sp
)
}
} else {
LazyColumn {
items(uiState.notificationList) { notification ->
NotificationList(
title = notification.title.toString(),
body = notification.body.toString(),
timestamp = notification.timestamp.toString()
)
}
}
}
}
NotificationUiState.Empty -> {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = stringResource(id = R.string.no_notification_found),
style = styleMedium16sp
)
}
}
}
}
}
@Composable
fun NotificationList(title: String, body: String, timestamp: String) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
shape = RoundedCornerShape(12.dp)
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(24.dp)
) {
Text(
text = title,
style = styleMedium16sp,
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 8.dp)
)
Text(
text = body, style = styleMedium16sp,
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 8.dp)
)
Text(
text = timestamp, style = historyItemTextStyle,
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 8.dp)
)
}
}
}
@Preview(showSystemUi = true, showBackground = true)
@Composable
private fun NotificationEmptyScreenPreview() {
NotificationScreen(uiState = NotificationUiState.Empty)
}
@Preview(showSystemUi = true, showBackground = true)
@Composable
private fun NotificationLoadingPreview() {
NotificationScreen(uiState = NotificationUiState.Loading)
}
@Preview(showSystemUi = true, showBackground = true)
@Composable
private fun NotificationSuccessPreview() {
NotificationScreen(uiState = NotificationUiState.Success(sampleNotificationList))
}
@Preview(showSystemUi = true, showBackground = true)
@Composable
private fun NotificationErrorScreenPreview() {
NotificationScreen(uiState = NotificationUiState.Error("Error Occurred"))
}
val sampleNotificationList = List(10) {
NotificationPayload("Title", "Body", "TimeStamp")
}