Skip to content

Draft: report migrate to cmp #2392

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

Open
wants to merge 25 commits into
base: kmp-impl
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
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
2 changes: 1 addition & 1 deletion cmp-navigation/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ kotlin {
implementation(projects.feature.note)
implementation(projects.feature.offline)
implementation(projects.feature.pathTracking)
// implementation(projects.feature.report)
implementation(projects.feature.report)
implementation(projects.feature.savings)
implementation(projects.feature.settings)
implementation(projects.feature.search)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.mifos.feature.auth.di.AuthModule
import com.mifos.feature.center.di.CenterModule
import com.mifos.feature.checker.inbox.task.di.CheckerInboxTaskModule
import com.mifos.feature.dataTable.di.DataTableModule
import com.mifos.feature.report.di.ReportModule
import com.mifos.feature.document.di.DocumentModule
import com.mifos.feature.groups.di.GroupsModule
import com.mifos.feature.individualCollectionSheet.di.CollectionSheetModule
Expand Down Expand Up @@ -75,7 +76,7 @@ object KoinModules {
NoteModule,
OfflineModule,
PathTrackingModule,
// ReportModule,
ReportModule,
SavingsModule,
SearchModule,
SettingsModule,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import com.mifos.feature.note.navigation.navigateToNoteScreen
import com.mifos.feature.note.navigation.noteNavGraph
import com.mifos.feature.offline.navigation.offlineNavGraph
import com.mifos.feature.pathTracking.navigation.pathTrackingNavGraph
import com.mifos.feature.report.navigation.reportNavGraph
import com.mifos.feature.savings.navigation.navigateToAddSavingsAccount
import com.mifos.feature.savings.navigation.navigateToSavingsAccountSummaryScreen
import com.mifos.feature.savings.navigation.savingsNavGraph
Expand Down Expand Up @@ -120,5 +121,7 @@ internal fun FeatureNavHost(
)

pathTrackingNavGraph(appState.navController)

reportNavGraph(navController = appState.navController)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,4 @@ fun MifosTextFieldDropdown(
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ import kotlinx.serialization.Serializable
*/
@Parcelize
@Serializable
data class DataRow(var row: List<String> = listOf()) : Parcelable
data class DataRow(var row: List<String?> = listOf()) : Parcelable
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,37 @@ package com.mifos.core.model.objects.runreport.client

import com.mifos.core.model.utils.Parcelable
import com.mifos.core.model.utils.Parcelize
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable


/**
* Created by Tarun on 03-08-17.
*/
@Parcelize
@Serializable
data class ClientReportTypeItem(
@SerialName("parameter_id")
var parameterId: Int? = null,

@SerialName("parameter_name")
var parameterName: String? = null,

@SerialName("report_category")
var reportCategory: String? = null,

@SerialName("report_id")
var reportId: Int? = null,

@SerialName("report_name")
var reportName: String? = null,

@SerialName("report_parameter_name")
var reportParameterName: String? = null,

@SerialName("report_subtype")
var reportSubtype: String? = null,

@SerialName("report_type")
var reportType: String? = null,
) : Parcelable
23 changes: 12 additions & 11 deletions feature/report/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,22 @@
* See https://github.com/openMF/android-client/blob/master/LICENSE.md
*/
plugins {
alias(libs.plugins.mifos.android.feature)
alias(libs.plugins.mifos.android.library.compose)
alias(libs.plugins.mifos.android.library.jacoco)
alias(libs.plugins.mifos.cmp.feature)
}

android {
namespace = "com.mifos.feature.report"
}

dependencies {

implementation(projects.core.domain)

//DBFlow dependencies
testImplementation(libs.hilt.android.testing)

implementation(libs.kotlinx.serialization.json)
kotlin {
sourceSets {
commonMain.dependencies {
implementation(compose.material3)
implementation(compose.components.resources)
implementation(compose.ui)
api(projects.core.domain)
implementation(libs.kotlinx.serialization.json)
implementation(compose.components.uiToolingPreview)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
*/
package com.mifos.feature.report.report

import android.Manifest
import android.os.Build
import android.os.Environment
import android.widget.Toast
import androidclient.feature.report.generated.resources.Res
import androidclient.feature.report.generated.resources.feature_report_dismiss
import androidclient.feature.report.generated.resources.feature_report_export_csv
import androidclient.feature.report.generated.resources.feature_report_external_approve_permission_description
import androidclient.feature.report.generated.resources.feature_report_permission_required
import androidclient.feature.report.generated.resources.feature_report_proceed
import androidclient.feature.report.generated.resources.feature_report_title
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyRow
Expand All @@ -33,22 +36,21 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color.Companion.Black
import androidx.compose.ui.graphics.Color.Companion.White
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
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.core.content.ContextCompat.getString
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import com.mifos.core.designsystem.component.MifosScaffold
import com.mifos.core.designsystem.component.PermissionBox
import com.mifos.core.designsystem.icon.MifosIcons
import com.mifos.core.model.objects.runreport.FullParameterListResponse
import com.mifos.feature.report.R
import kotlinx.coroutines.launch
import org.koin.androidx.compose.koinViewModel
import org.jetbrains.compose.resources.stringResource
import org.koin.compose.viewmodel.koinViewModel
import org.jetbrains.compose.ui.tooling.preview.Preview
import org.jetbrains.compose.ui.tooling.preview.PreviewParameter
import org.jetbrains.compose.ui.tooling.preview.PreviewParameterProvider


@Composable
internal fun ReportScreen(
Expand All @@ -57,20 +59,19 @@ internal fun ReportScreen(
) {
val report = viewModel.report
val state by viewModel.reportUiState.collectAsStateWithLifecycle()
val context = LocalContext.current

ReportScreen(
state = state,
report = report,
onBackPressed = onBackPressed,
exportReport = {
val reportDirectoryPath =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
.toString() + getString(context, R.string.feature_report_export_csv_directory)
viewModel.exportCsv(
report = report,
reportDirectoryPath = reportDirectoryPath,
)
// val reportDirectoryPath =
// Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
// .toString() + getString(context, R.string.feature_report_export_csv_directory)
// viewModel.exportCsv(
// report = report,
// reportDirectoryPath = reportDirectoryPath,
// )
},
)
}
Expand All @@ -83,45 +84,44 @@ internal fun ReportScreen(
modifier: Modifier = Modifier,
exportReport: () -> Unit,
) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
val snackbarHostState = remember { SnackbarHostState() }
var checkPermission by remember { mutableStateOf(false) }

when (state) {
is ReportUiState.Initial -> Unit
is ReportUiState.Message -> {
Toast.makeText(context, stringResource(id = state.message), Toast.LENGTH_SHORT).show()
// Toast.makeText(context, stringResource(state.message), Toast.LENGTH_SHORT).show()
}
}

if (checkPermission) {
PermissionBox(
requiredPermissions = if (Build.VERSION.SDK_INT >= 33) {
listOf(Manifest.permission.READ_MEDIA_IMAGES)
} else {
listOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
)
},
title = stringResource(R.string.feature_report_permission_required),
description = stringResource(R.string.feature_report_external_approve_permission_description),
confirmButtonText = stringResource(R.string.feature_report_proceed),
dismissButtonText = stringResource(R.string.feature_report_dismiss),
onGranted = {
LaunchedEffect(key1 = Unit) {
scope.launch {
exportReport()
}
}
},
)
// PermissionBox(
// requiredPermissions = if (Build.VERSION.SDK_INT >= 33) {
// listOf(Manifest.permission.READ_MEDIA_IMAGES)
// } else {
// listOf(
// Manifest.permission.READ_EXTERNAL_STORAGE,
// Manifest.permission.WRITE_EXTERNAL_STORAGE,
// )
// },
// title = Res.string.feature_report_permission_required,
// description = Res.string.feature_report_external_approve_permission_description,
// confirmButtonText = Res.string.feature_report_proceed,
// dismissButtonText = Res.string.feature_report_dismiss,
// onGranted = {
// LaunchedEffect(key1 = Unit) {
// scope.launch {
// exportReport()
// }
// }
// },
// )
}

MifosScaffold(
modifier = modifier,
title = stringResource(R.string.feature_report_title),
title = stringResource(Res.string.feature_report_title),
onBackPressed = onBackPressed,
actions = {
TextButton(
Expand All @@ -130,7 +130,7 @@ internal fun ReportScreen(
},
colors = ButtonDefaults.textButtonColors(White),
) {
Text(text = stringResource(id = R.string.feature_report_export_csv), color = Black)
Text(text = stringResource(Res.string.feature_report_export_csv))
}
},
snackbarHostState = snackbarHostState,
Expand All @@ -152,7 +152,9 @@ internal fun ReportScreen(
),
)
report.data.map { it.row }.forEach {
Text(text = it[index], modifier = Modifier.padding(8.dp))
if (it[index] != null) {
Text(text = it[index]!!, modifier = Modifier.padding(8.dp))
}
}
}
}
Expand All @@ -166,11 +168,11 @@ private class ReportUiStateProvider : PreviewParameterProvider<ReportUiState> {
override val values: Sequence<ReportUiState>
get() = sequenceOf(
ReportUiState.Initial,
ReportUiState.Message(R.string.feature_report_export_csv),
ReportUiState.Message(Res.string.feature_report_export_csv),
)
}

@Preview(showBackground = true)
@Preview
@Composable
private fun ReportScreenPreview(
@PreviewParameter(ReportUiStateProvider::class) state: ReportUiState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
*/
package com.mifos.feature.report.report

import org.jetbrains.compose.resources.StringResource

sealed class ReportUiState {

data object Initial : ReportUiState()

data class Message(val message: Int) : ReportUiState()
data class Message(val message: StringResource) : ReportUiState()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
///*
// * Copyright 2024 Mifos Initiative
// *
// * This Source Code Form is subject to the terms of the Mozilla Public
// * License, v. 2.0. If a copy of the MPL was not distributed with this
// * file, You can obtain one at https://mozilla.org/MPL/2.0/.
// *
// * See https://github.com/openMF/android-client/blob/master/LICENSE.md
// */
package com.mifos.feature.report.report


import androidclient.feature.report.generated.resources.Res
import androidclient.feature.report.generated.resources.feature_report_export_started
import androidclient.feature.report.generated.resources.feature_report_exported_successfully
import androidclient.feature.report.generated.resources.feature_report_unable_to_export
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.mifos.core.common.utils.Constants
import com.mifos.core.model.objects.runreport.FullParameterListResponse
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import kotlinx.datetime.Clock
import kotlinx.serialization.json.Json
import okio.FileSystem
import okio.Path.Companion.toPath
import okio.SYSTEM
import okio.buffer
import okio.use

class ReportViewModel(
savedStateHandle: SavedStateHandle,
) : ViewModel() {

private val reportParameterString =
savedStateHandle.getStateFlow(key = Constants.REPORT_PARAMETER_RESPONSE, initialValue = "")

val report: FullParameterListResponse =
Json.decodeFromString(reportParameterString.value)

private val _reportUiState = MutableStateFlow<ReportUiState>(ReportUiState.Initial)
val reportUiState = _reportUiState.asStateFlow()

fun exportCsv(report: FullParameterListResponse, reportDirectoryPath: String) {
viewModelScope.launch {
_reportUiState.value = ReportUiState.Message(Res.string.feature_report_export_started)

val timestamp = Clock.System.now().toEpochMilliseconds().toString()
val fileName = "$reportDirectoryPath/$timestamp.csv"
val path = fileName.toPath()

try {
FileSystem.SYSTEM.sink(path).buffer().use { sink ->
val headers = report.columnHeaders.joinToString(",") { it.columnName }
sink.writeUtf8(headers + "\n")

for (row in report.data) {
val line = row.row.joinToString(",")
sink.writeUtf8(line + "\n")
}
}

_reportUiState.value =
ReportUiState.Message(Res.string.feature_report_exported_successfully)
} catch (e: Exception) {
_reportUiState.value =
ReportUiState.Message(Res.string.feature_report_unable_to_export)
}
}
}
}
Loading
Loading