Skip to content

Conversation

@revanthkumarJ
Copy link
Contributor

@revanthkumarJ revanthkumarJ commented Mar 28, 2025

Fixes - Jira-#402

Didn't create a Jira ticket, click here to create new.

Please Add Screenshots If there are any UI changes.

Before After

Please make sure these boxes are checked before submitting your pull request - thanks!

  • Run the static analysis check ./gradlew check or ci-prepush.sh to make sure you didn't break anything

  • If you have multiple commits please combine them into one commit by squashing them.

@revanthkumarJ revanthkumarJ changed the title initial setup refactor (core:network ) Network converted to KMP Mar 28, 2025
@revanthkumarJ revanthkumarJ marked this pull request as ready for review April 14, 2025 16:44
@revanthkumarJ
Copy link
Contributor Author

@biplab1 review it once if things are ok then we can merge this and complete the data and domain next

Copy link
Contributor

@biplab1 biplab1 left a comment

Choose a reason for hiding this comment

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

These are some minor changes that needs to be addressed.

Also, add @OptIn(ExperimentalCoroutinesApi::class) to functions using flatMapLatest in DataManagers

if (dueDateList.size > 2) {
return String.format(pattern, dueDateList[0], dueDateList[1], dueDateList[2])
return ""
// return String.format(pattern, dueDateList[0], dueDateList[1], dueDateList[2])
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you tell me the reason for commenting out this code?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

by mistake uncommented it

Comment on lines 14 to 15
id("kotlinx-serialization")
id("com.google.devtools.ksp")
Copy link
Contributor

Choose a reason for hiding this comment

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

Please use version catalog instead:

alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.ksp)

}

suspend fun getRechdeduleLoansTaskList(): List<com.mifos.core.model.objects.checkerinboxtask.RescheduleLoansTask> {
return mBaseApiManager.checkerInboxApi.getRescheduleLoansTaskList()
Copy link
Contributor

Choose a reason for hiding this comment

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

"getRechdeduleLoansTaskList" should be "getRescheduleLoansTaskList"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't understood . It's already getRescheduleLoansTaskList

Copy link
Contributor

Choose a reason for hiding this comment

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

image

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

resourceId: Int?,
): Flow<List<CheckerTask>> {
return flow { emit(dataManagerCheckerInbox.getCheckerTaskList()) }
return dataManagerCheckerInbox.getCheckerTaskList()
Copy link
Contributor

Choose a reason for hiding this comment

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

So due to Github limitation, I cannot comment on the lines that are outside this PR, so I am adding it here. In line no. 27 of this file,
"getRechdeduleLoansTaskList" should be "getRescheduleLoansTaskList"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

)
clientsTemplate
}
flow {
Copy link
Contributor

Choose a reason for hiding this comment

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

clientTemplate should be marked with @OptIn(ExperimentalCoroutinesApi::class)

 @OptIn(ExperimentalCoroutinesApi::class)
 val clientTemplate: Flow<ClientsTemplateEntity>

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@Serializable
data class GetCentersResponse(

val pageItems: kotlin.collections.Set<GetCentersPageItems>? = null,
Copy link
Contributor

Choose a reason for hiding this comment

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

kotlin.collections is redundant here and can be removed.

Similarly, other files in :core:network:model makes use of it, please check and update.


val columnName: kotlin.String? = null,

val columnType: ResultsetColumnHeaderData.ColumnType? = null,
Copy link
Contributor

Choose a reason for hiding this comment

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

Here ResultsetColumnHeaderData is redundant. It is better to remove. There are two occurrences in this file.

Copy link
Contributor

Choose a reason for hiding this comment

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

Please use an alternative to import java.util.Date which is compatible with KMP. Try using
import kotlinx.datetime.Instant and Instant in place of Date data type.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done


@GET(APIEndPoint.MAKER_CHECKER + "/searchtemplate?fields=entityNames,actionNames")
fun getCheckerInboxSearchTempalate(): Observable<CheckerInboxSearchTemplate>
fun getCheckerInboxSearchTempalate(): Flow<CheckerInboxSearchTemplate>
Copy link
Contributor

Choose a reason for hiding this comment

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

getCheckerInboxSearchTempalate should be getCheckerInboxSearchTemplate. Please make appropriate changes in places where it is used.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

Copy link
Contributor

Choose a reason for hiding this comment

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

Line 40: saveindividualCollectionSheet should be saveIndividualCollectionSheet. Also, make changes where it is used.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@biplab1
Copy link
Contributor

biplab1 commented Apr 17, 2025

@revanthkumarJ Just a quick note for future reference — it's best to leave the review comments unresolved even after you've fixed them. That way, maintainers and reviewers can go through and verify the changes before marking them resolved.

@HekmatullahAmin
Copy link
Member

HekmatullahAmin commented Apr 17, 2025

@revanthkumarJ I have seen below in many places I give an example change all of them accordingly.

  • In some Places you changed the data types from nullable to non nullable be careful with it.

  • Also in some places you have asserted not null !! be careful with it

  • when you change the api call to return stream then change it in all places it gets called.

Api

interface CenterService {
    @GET(APIEndPoint.CENTERS)
    fun getAllCentersInOffice(
        @Query("officeId") officeId: Int,
        @QueryMap additionalParams: Map<String, String>,
    ): Flow<List<CenterEntity>>
}

DataManager

class DataManager @Inject constructor(private val mBaseApiManager: BaseApiManager) {
    fun getCentersInOffice(id: Int, params: Map<String, String>): Flow<List<CenterEntity>> {
        return mBaseApiManager.centerApi.getAllCentersInOffice(id, params)
    }
}

Repository

class GenerateCollectionSheetRepositoryImp @Inject constructor(
    private val dataManager: DataManager,
) : GenerateCollectionSheetRepository {

    override fun getCentersInOffice(id: Int, params: Map<String, String>): Flow<List<CenterEntity>> {
        return dataManager.getCentersInOffice(id, params)
    }
}

UseCase (it is just an example fix it accordingly)

class GetCentersInOfficeUseCase @Inject constructor(
    private val repository: GenerateCollectionSheetRepository,
) {
    operator fun invoke(id: Int, params: Map<String, String>): Flow<Resource<List<CenterEntity>>> =
        repository.getCentersInOffice(id, params)
            .map { Resource.Success(it) }
            .catch { emit(Resource.Error(it.message ?: "Unknown error")) }
            .onStart { emit(Resource.Loading()) }
}

interface GenerateCollectionSheetRepository {

suspend fun getCentersInOffice(id: Int, params: Map<String, String>): List<CenterEntity>
suspend fun getCentersInOffice(id: Int, params: Map<String, String>): Flow<List<CenterEntity>>
Copy link
Member

Choose a reason for hiding this comment

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

why some functions like these are at the same time suspend and flowable

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok i will resolve them . actually they belongs to data module at first i tried to resolve the things to make application run but later Rajan sir told that it will be done during data module migration

Copy link
Member

Choose a reason for hiding this comment

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

@revanthkumarJ ok then keep your scope to your own and change it to where it belongs to your module. If it is sth like that can you revert it back so someone who works in data module should get any conflicts. and for them it might be confusing like ok it's suspend and at the same time stream and they keep it


@GET(APIEndPoint.GROUPS)
suspend fun getAllGroupsInOffice(
fun getAllGroupsInOffice(
Copy link
Member

Choose a reason for hiding this comment

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

I see the API call previously was suspend not a stream. so keep it suspend. and you manually wrap it in flow {} at repository layer or wherever it is called.

Copy link
Member

Choose a reason for hiding this comment

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

Or in the above i provided an example if you change it to stream how to do it. In chain some places you added both suspent and return type flow, in some places you removed suspend.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

in nagarjuna pr niyaj brother mentioned that if any service returns list make it flow and remove suspend i followed that .

Copy link
Member

Choose a reason for hiding this comment

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

yes cause of that in my second message i mentioned that if you remove the suspend and add flow what you should do in other files that calls it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yah after the domain and data are merged we have to change in all feature modules where they are called.
In mifos-mobile we have done similarly

Copy link
Contributor Author

@revanthkumarJ revanthkumarJ Apr 17, 2025

Choose a reason for hiding this comment

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

What niyaj mentioned in mifos-mobile network module conversion is

Few things to change I'm commenting on one place

if the function return as List or Observable then convert into Flow<List> or Flow
If the function return as a Flow then that shouldn't be suspend fun, so remove suspend modifier from function.

override suspend fun uploadClientImage(id: Int, file: MultipartBody.Part?) {
dataManagerClient.uploadClientImage(id, file)
override suspend fun uploadClientImage(id: Int, file: PartData?) {
// dataManagerClient.uploadClientImage(id, file)
Copy link
Member

Choose a reason for hiding this comment

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

why you commented this one?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

uncommneted it was a mistake


override fun offices(): Flow<List<OfficeEntity>> {
return dataManagerOffices.offices()
return dataManagerOffices.offices
Copy link
Member

Choose a reason for hiding this comment

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

previously it was calling offices() from DataManagerOffices, which you changed it to fetchOffices. But now you are calling offices not fetchOffices. what is the reason?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

resolved, used fetchoffices()

): Flow<SavingsAccountTransactionTemplateEntity?> {
return dataManagerSavings.getSavingsAccountTransactionTemplate(
type,
type!!,
Copy link
Member

Choose a reason for hiding this comment

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

  • Don't force it like this in here that it is not null. If it is always not null then change the type type to String wherever it is called.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

* This Method Request the REST API of Note and In response give the List of Notes
*/
fun getNotes(entityType: String?, entityId: Int): List<Note> {
fun getNotes(entityType: String, entityId: Int): List<Note> {
Copy link
Member

Choose a reason for hiding this comment

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

you changed the entityType type from String? to String. are you sure that when this function is called they entityType is not null, and also the actual api getNotes(...) only accept String cause of that you changed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The reason i done that is when i runned the application it showed the error like path parameter in ktorfit should not be null

.apply {
logger(DebugLogger())
}.build()
single { (context: Any) ->
Copy link
Member

Choose a reason for hiding this comment

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

This DI injection looks so messy. I haven't work on network, but ask @niyajali to review this file for you.

code = entity.status?.code,
value = entity.status?.description,
code = entity.status.code,
value = entity.status.description,
Copy link
Member

Choose a reason for hiding this comment

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

Does GetGroupsStatus code and description is not nullable that you removed safe call?

Copy link
Member

Choose a reason for hiding this comment

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

I don't think so so make it safe call

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@get:GET(APIEndPoint.CLIENTS + "/template")
val clientTemplate: Flow<ClientsTemplateEntity>
@GET(APIEndPoint.CLIENTS + "/template")
suspend fun getClientTemplate(): ClientsTemplateEntity
Copy link
Member

Choose a reason for hiding this comment

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

why you are making it suspend when it is stream

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it is not stream the below function to it is Flow it is not suspend function

entityName: String? = null,
resourceId: Int? = null,
): List<CheckerTask>
): Flow<List<CheckerTask>>
Copy link
Member

Choose a reason for hiding this comment

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

when it is suspend why adding flow, maybe in the UseCase that it is called it will call this suspend function and then emit it accordigly

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@revanthkumarJ
Copy link
Contributor Author

@biplab1 @HekmatullahAmin i have done all the suggestions you guys mentioned , see it once if i have missed anything let me know before standup i will do it

interface ClientDetailsRepository {

suspend fun uploadClientImage(id: Int, file: MultipartBody.Part?)
suspend fun uploadClientImage(id: Int, file: PartData?)
Copy link
Contributor

Choose a reason for hiding this comment

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

Are these two equivalent— okhttp3.MultipartBody and io.ktor.http.content.PartData? They must be having different APIs and hence different implementations.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes they have different implementations , while passing the the things in domain we have to take care of it

Copy link
Contributor Author

@revanthkumarJ revanthkumarJ Apr 17, 2025

Choose a reason for hiding this comment

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

I have taken reference from mifos-wallet there MultipartBody.Part? is replaced with PartData

Copy link
Contributor Author

Choose a reason for hiding this comment

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

From mobile-wallet network module conversion PR
image

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for the information

@therajanmaurya therajanmaurya merged commit befb189 into openMF:kmp-impl Apr 18, 2025
5 checks passed
itsPronay pushed a commit to itsPronay/android-client that referenced this pull request Aug 5, 2025
* initial setup

* updated

* Updated

* Changed Imports in Services

* Updated

* Updated

* Added ktorHttpClient

* Added ktorHttpClient

* Updated

* Updated

* Updated

* updated mappers

* updated mappers

* Updated

* Updated

* Updated

* Updated

* Updated

* Updated ImageLoader.Utils

* changed observable to flow in data

* Updated

* Updated

* Updated

* Updated based on suggestions

* Updated

* Updated

* Updated
itsPronay pushed a commit to itsPronay/android-client that referenced this pull request Aug 5, 2025
* initial setup

* updated

* Updated

* Changed Imports in Services

* Updated

* Updated

* Added ktorHttpClient

* Added ktorHttpClient

* Updated

* Updated

* Updated

* updated mappers

* updated mappers

* Updated

* Updated

* Updated

* Updated

* Updated

* Updated ImageLoader.Utils

* changed observable to flow in data

* Updated

* Updated

* Updated

* Updated based on suggestions

* Updated

* Updated

* Updated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants