Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: refactor Group list fragment to compose #2135

Merged
merged 1 commit into from
Jul 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion core/data/src/main/java/com/mifos/core/data/di/DataModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.mifos.core.data.repository.ClientIdentifiersRepository
import com.mifos.core.data.repository.CreateNewCenterRepository
import com.mifos.core.data.repository.DocumentListRepository
import com.mifos.core.data.repository.GroupDetailsRepository
import com.mifos.core.data.repository.GroupListRepository
import com.mifos.core.data.repository.GroupsListRepository
import com.mifos.core.data.repository.LoanAccountRepository
import com.mifos.core.data.repository.NewIndividualCollectionSheetRepository
Expand All @@ -25,6 +26,7 @@ import com.mifos.core.data.repository_imp.ClientIdentifiersRepositoryImp
import com.mifos.core.data.repository_imp.CreateNewCenterRepositoryImp
import com.mifos.core.data.repository_imp.DocumentListRepositoryImp
import com.mifos.core.data.repository_imp.GroupDetailsRepositoryImp
import com.mifos.core.data.repository_imp.GroupListRepositoryImp
import com.mifos.core.data.repository_imp.GroupsListRepositoryImpl
import com.mifos.core.data.repository_imp.LoanAccountRepositoryImp
import com.mifos.core.data.repository_imp.NewIndividualCollectionSheetRepositoryImp
Expand Down Expand Up @@ -80,10 +82,13 @@ abstract class DataModule {

@Binds
internal abstract fun bindReportDetailRepository(impl: ReportDetailRepositoryImp): ReportDetailRepository

@Binds
internal abstract fun bindLoanAccountRepository(impl: LoanAccountRepositoryImp): LoanAccountRepository

@Binds
internal abstract fun bindDocumentListRepository(impl: DocumentListRepositoryImp): DocumentListRepository

@Binds
internal abstract fun bindGroupListRepository(impl: GroupListRepositoryImp): GroupListRepository
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.mifos.mifosxdroid.online.grouplist
package com.mifos.core.data.repository

import com.mifos.core.objects.group.CenterWithAssociations
import com.mifos.core.objects.group.GroupWithAssociations
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.mifos.mifosxdroid.online.grouplist
package com.mifos.core.data.repository_imp

import com.mifos.core.data.repository.GroupListRepository
import com.mifos.core.network.DataManager
import com.mifos.core.objects.group.CenterWithAssociations
import com.mifos.core.objects.group.GroupWithAssociations
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.mifos.core.domain.use_cases

import com.mifos.core.common.utils.Resource
import com.mifos.core.data.repository.GroupListRepository
import com.mifos.core.objects.group.CenterWithAssociations
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import rx.Subscriber
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
import javax.inject.Inject

class GetGroupsByCenterUseCase @Inject constructor(private val repository: GroupListRepository) {

suspend operator fun invoke(id: Int): Flow<Resource<CenterWithAssociations>> = callbackFlow {
try {
trySend(Resource.Loading())
repository.getGroupsByCenter(id)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(object : Subscriber<CenterWithAssociations>() {
override fun onCompleted() {
}

override fun onError(e: Throwable) {
trySend(Resource.Error(e.message.toString()))
}

override fun onNext(centerWithAssociations: CenterWithAssociations) {
trySend(Resource.Success(centerWithAssociations))
}
})

awaitClose { channel.close() }
} catch (exception: Exception) {
send(Resource.Error(exception.message.toString()))
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.mifos.core.domain.use_cases

import com.mifos.core.common.utils.Resource
import com.mifos.core.data.repository.GroupListRepository
import com.mifos.core.objects.group.GroupWithAssociations
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import rx.Subscriber
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
import javax.inject.Inject

class GetGroupsUseCase @Inject constructor(private val repository: GroupListRepository) {

suspend operator fun invoke(groupId: Int): Flow<Resource<GroupWithAssociations>> =
callbackFlow {
try {
trySend(Resource.Loading())
repository.getGroups(groupId)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(object : Subscriber<GroupWithAssociations>() {
override fun onCompleted() {}

override fun onError(exception: Throwable) {
trySend(Resource.Error(exception.message.toString()))
}

override fun onNext(groupWithAssociations: GroupWithAssociations) {
trySend(Resource.Success(groupWithAssociations))
}
})

awaitClose { channel.close() }
} catch (exception: Exception) {
trySend(Resource.Error(exception.message.toString()))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
package com.mifos.feature.center.center_group_list

import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
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.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.mifos.core.designsystem.component.MifosCircularProgress
import com.mifos.core.designsystem.component.MifosScaffold
import com.mifos.core.designsystem.component.MifosSweetError
import com.mifos.core.designsystem.icon.MifosIcons
import com.mifos.core.objects.client.Client
import com.mifos.core.objects.client.Status
import com.mifos.core.objects.group.CenterWithAssociations
import com.mifos.core.objects.group.Group
import com.mifos.core.ui.components.MifosEmptyUi
import com.mifos.feature.center.R

@Composable
fun GroupListScreen(
centerId: Int,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rajan bhaiya told us to move them into viewmodel

" when we will delete the fragment and use directly compose UI then we will pass this id through nav args in ViewModel so we don't need refactor it later"

onBackPressed: () -> Unit,
loadClientsOfGroup: (List<Client>) -> Unit
) {

val viewModel: GroupListViewModel = hiltViewModel()
val state by viewModel.groupListUiState.collectAsStateWithLifecycle()
val groupAssociationState by viewModel.groupAssociationState.collectAsStateWithLifecycle()
var groupClicked by remember { mutableStateOf(false) }

LaunchedEffect(key1 = groupAssociationState) {
groupAssociationState?.let {
if (groupClicked) {
loadClientsOfGroup(it.clientMembers)
}
}
}

LaunchedEffect(key1 = Unit) {
viewModel.loadGroupByCenter(centerId)
}

GroupListScreen(
state = state,
onBackPressed = onBackPressed,
onGroupClick = {
groupClicked = true
viewModel.loadGroups(it)
},
onRetry = {
viewModel.loadGroupByCenter(centerId)
}
)
}

@Composable
fun GroupListScreen(
state: GroupListUiState,
onBackPressed: () -> Unit,
onRetry: () -> Unit,
onGroupClick: (Int) -> Unit
) {
val snackbarHostState = remember { SnackbarHostState() }

MifosScaffold(
icon = MifosIcons.arrowBack,
title = stringResource(id = R.string.feature_center_groups),
onBackPressed = onBackPressed,
snackbarHostState = snackbarHostState
) { paddingValues ->
Column(modifier = Modifier.padding(paddingValues)) {
when (state) {
is GroupListUiState.Error -> MifosSweetError(message = stringResource(id = state.message)) {
onRetry()
}

is GroupListUiState.Loading -> MifosCircularProgress()

is GroupListUiState.GroupList -> {
if (state.centerWithAssociations.groupMembers.isEmpty()) {
MifosEmptyUi(
text = stringResource(id = R.string.feature_center_no_group_list_to_show),
icon = MifosIcons.fileTask
)
} else {
GroupListContent(
centerWithAssociations = state.centerWithAssociations,
onGroupClick = onGroupClick
)
}
}
}
}
}
}


@Composable
fun GroupListContent(
centerWithAssociations: CenterWithAssociations,
onGroupClick: (Int) -> Unit
) {
LazyColumn {
items(centerWithAssociations.groupMembers) { group ->
GroupItem(group = group, onGroupClick = onGroupClick)
}
}
}


@Composable
fun GroupItem(
group: Group,
onGroupClick: (Int) -> Unit
) {
Card(
modifier = Modifier
.fillMaxWidth(),
shape = RoundedCornerShape(0.dp),
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp),
colors = CardDefaults.cardColors(
containerColor = Color.White
),
onClick = { group.id?.let { onGroupClick(it) } }
) {
Column(modifier = Modifier.padding(8.dp)) {
Row(
modifier = Modifier
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(
modifier = Modifier
.padding(8.dp),
text = group.name.toString(),
style = MaterialTheme.typography.bodyMedium
)
Text(
modifier = Modifier.padding(8.dp),
text = group.officeName.toString(),
style = MaterialTheme.typography.bodyMedium,
)
}
Row(verticalAlignment = Alignment.CenterVertically) {
Text(
modifier = Modifier.padding(8.dp),
style = MaterialTheme.typography.bodySmall,
text = if (group.status?.value?.let { Status.isActive(it) } == true) {
stringResource(id = R.string.feature_center_active)
} else {
stringResource(id = R.string.feature_center_inactive)
}
)
Canvas(modifier = Modifier.size(16.dp)) {
if (group.status?.value?.let { Status.isActive(it) } == true) {
drawRect(Color.Green)
} else {
drawRect(Color.Red)
}
}
}
}
}
HorizontalDivider()
}

class GroupListUiStateProvider : PreviewParameterProvider<GroupListUiState> {

override val values: Sequence<GroupListUiState>
get() = sequenceOf(
GroupListUiState.Loading,
GroupListUiState.Error(R.string.feature_center_failed_to_load_group_list),
GroupListUiState.GroupList(sampleCenterWithAssociations)
)
}

@Preview(showBackground = true)
@Composable
private fun GroupListScreenPreview(
@PreviewParameter(GroupListUiStateProvider::class) state: GroupListUiState
) {
GroupListScreen(
state = state,
onBackPressed = {},
onGroupClick = {},
onRetry = {}
)
}

val sampleCenterWithAssociations = CenterWithAssociations()
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.mifos.feature.center.center_group_list

import com.mifos.core.objects.group.CenterWithAssociations

/**
* Created by Aditya Gupta on 06/08/23.
*/
sealed class GroupListUiState {

data object Loading : GroupListUiState()

data class Error(val message: Int) : GroupListUiState()

data class GroupList(val centerWithAssociations: CenterWithAssociations) : GroupListUiState()
}
Loading
Loading