Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 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
76 changes: 76 additions & 0 deletions app/src/main/java/org/groundplatform/android/di/PdfReportModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.groundplatform.android.di

import android.content.Context
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
import kotlinx.coroutines.CoroutineDispatcher
import org.groundplatform.android.BuildConfig
import org.groundplatform.android.R
import org.groundplatform.android.di.coroutines.IoDispatcher
import org.groundplatform.ui.system.pdf.AndroidPdfRenderer
import org.groundplatform.ui.system.pdf.PdfExportService
import org.groundplatform.ui.system.pdf.PdfRenderer
import org.groundplatform.ui.system.pdf.image.AndroidPdfImageProvider
import org.groundplatform.ui.system.pdf.image.PdfImageProvider
import org.groundplatform.ui.system.pdf.io.AndroidPdfOutputProvider
import org.groundplatform.ui.system.pdf.io.AndroidPdfReportLauncher
import org.groundplatform.ui.system.pdf.io.PdfOutputProvider
import org.groundplatform.ui.system.pdf.io.PdfReportLauncher

@Module
@InstallIn(SingletonComponent::class)
object PdfReportModule {

@Provides
@Singleton
fun providePdfImageProvider(@ApplicationContext context: Context): PdfImageProvider =
AndroidPdfImageProvider(context = context, logoDrawableRes = R.drawable.ground_logo)

@Provides
@Singleton
fun providePdfOutputFactory(@ApplicationContext context: Context): PdfOutputProvider =
AndroidPdfOutputProvider(context)

@Provides @Singleton fun providePdfRenderer(): PdfRenderer = AndroidPdfRenderer()

@Provides
@Singleton
fun providePdfReportLauncher(@ApplicationContext context: Context): PdfReportLauncher =
AndroidPdfReportLauncher(context = context, fileProviderAuthority = BuildConfig.APPLICATION_ID)

@Provides
@Singleton
fun providePdfReportService(
imageProvider: PdfImageProvider,
renderer: PdfRenderer,
outputProvider: PdfOutputProvider,
launcher: PdfReportLauncher,
@IoDispatcher coroutineDispatcher: CoroutineDispatcher,
): PdfExportService =
PdfExportService(
imageProvider = imageProvider,
renderer = renderer,
outputProvider = outputProvider,
launcher = launcher,
coroutineDispatcher = coroutineDispatcher,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,14 @@ object UseCaseModule {
locationOfInterestRepository: LocationOfInterestRepositoryInterface,
userRepository: UserRepositoryInterface,
surveyRepository: SurveyRepositoryInterface,
) = GetLoiReportUseCase(locationOfInterestRepository, userRepository, surveyRepository)
submissionRepository: SubmissionRepositoryInterface,
) =
GetLoiReportUseCase(
locationOfInterestRepository = locationOfInterestRepository,
userRepositoryInterface = userRepository,
surveyRepositoryInterface = surveyRepository,
submissionRepositoryInterface = submissionRepository,
)

@Provides
fun providesUpdateUserSettingsUseCase(userRepository: UserRepositoryInterface) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,7 @@ constructor(

private suspend fun getPendingDeleteCount(loiId: String) =
localSubmissionStore.getPendingDeleteCount(loiId)

override suspend fun getSubmissions(loi: LocationOfInterest) =
localSubmissionStore.getSubmissions(loi, loi.job.id)
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,27 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.hilt.navigation.fragment.hiltNavGraphViewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
import kotlinx.coroutines.launch
import org.groundplatform.android.R
import org.groundplatform.android.ui.common.AbstractFragment
import org.groundplatform.android.ui.common.BackPressListener
import org.groundplatform.android.ui.common.EphemeralPopups
import org.groundplatform.android.ui.home.HomeScreenViewModel
import org.groundplatform.android.util.createComposeView
import org.groundplatform.android.util.openAppSettings
import javax.inject.Inject
import org.groundplatform.ui.components.loireport.LoiReportAction
import org.groundplatform.ui.mapper.LoiReportMapper
import org.groundplatform.ui.system.pdf.PdfExportService

/** Fragment allowing the user to collect data to complete a task. */
@AndroidEntryPoint
class DataCollectionFragment : AbstractFragment(), BackPressListener {
@Inject lateinit var popups: EphemeralPopups
@Inject lateinit var pdfExportService: PdfExportService

val viewModel: DataCollectionViewModel by hiltNavGraphViewModels(R.id.data_collection)

Expand All @@ -55,6 +61,7 @@ class DataCollectionFragment : AbstractFragment(), BackPressListener {
onExitConfirmed = { navigateBack() },
onOpenSettings = { requireActivity().openAppSettings() },
onAwaitingPhotoCapture = { homeScreenViewModel.awaitingPhotoCapture = it },
onLoiReportAction = { handleLoiReportAction(it) },
)
}

Expand Down Expand Up @@ -91,6 +98,35 @@ class DataCollectionFragment : AbstractFragment(), BackPressListener {
findNavController().navigateUp()
}

private fun handleLoiReportAction(action: LoiReportAction) {
val loiReport =
(viewModel.uiState.value as? DataCollectionUiState.TaskSubmitted)?.loiReport
?: run {
popups.ErrorPopup().unknownError()
return
}
val submission =
loiReport.submissionDetails?.submissions?.firstOrNull()
?: run {
popups.ErrorPopup().unknownError()
return
}

lifecycleScope.launch {
val request = LoiReportMapper.map(loiReport, submission)
if (request == null) {
popups.ErrorPopup().unknownError()
return@launch
}
val pdfAction =
when (action) {
is LoiReportAction.OnShareClicked -> PdfExportService.Action.Share
is LoiReportAction.OnPdfItemClicked -> PdfExportService.Action.Open
}
pdfExportService.export(request, pdfAction)
}
}

companion object {
const val TASK_ID: String = "taskId"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import org.groundplatform.android.R
import org.groundplatform.android.ui.components.ConfirmationDialog
import org.groundplatform.android.ui.datacollection.tasks.TaskScreenContainer
import org.groundplatform.ui.components.loireport.LoiReportAction

/**
* The main screen for data collection, coordinating the task sequence and host UI.
Expand All @@ -57,6 +58,7 @@ import org.groundplatform.android.ui.datacollection.tasks.TaskScreenContainer
fun DataCollectionScreen(
viewModel: DataCollectionViewModel,
onValidationError: (resId: Int) -> Unit,
onLoiReportAction: (LoiReportAction) -> Unit,
onExitConfirmed: () -> Unit,
onOpenSettings: () -> Unit,
onAwaitingPhotoCapture: (Boolean) -> Unit,
Expand All @@ -75,7 +77,11 @@ fun DataCollectionScreen(
}
}

DataCollectionContent(uiState = uiState, onCloseClicked = { viewModel.onCloseClicked() }) {
DataCollectionContent(
uiState = uiState,
onCloseClicked = { viewModel.onCloseClicked() },
onLoiReportAction = onLoiReportAction,
) {
readyState ->
val tasks = readyState.tasks
if (tasks.isNotEmpty()) {
Expand Down Expand Up @@ -134,6 +140,7 @@ object DataCollectionScreenTestTags {
fun DataCollectionContent(
uiState: DataCollectionUiState,
onCloseClicked: () -> Unit,
onLoiReportAction: (LoiReportAction) -> Unit,
pagerContent: @Composable (DataCollectionUiState.Ready) -> Unit,
) {
Scaffold(topBar = { DataCollectionToolbar(uiState, onCloseClicked) }) { innerPadding ->
Expand All @@ -153,7 +160,11 @@ fun DataCollectionContent(
ReadyContent { pagerContent(uiState) }
}
is DataCollectionUiState.TaskSubmitted -> {
DataSubmissionConfirmationScreen(loiReport = uiState.loiReport) { onCloseClicked() }
DataSubmissionConfirmationScreen(
loiReport = uiState.loiReport,
onLoiReportAction = onLoiReportAction,
onDismissed = onCloseClicked,
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import kotlin.time.Clock
import kotlinx.serialization.json.JsonObject
import org.groundplatform.android.ui.common.ExcludeFromJacocoGeneratedReport
import org.groundplatform.domain.model.job.Job
Expand All @@ -38,7 +37,11 @@ private const val PAGER_CONTENT_TEXT = "Pager Content Area"
@ExcludeFromJacocoGeneratedReport
private fun DataCollectionContentLoadingPreview() {
AppTheme {
DataCollectionContent(uiState = DataCollectionUiState.Loading, onCloseClicked = {}) {
DataCollectionContent(
uiState = DataCollectionUiState.Loading,
onCloseClicked = {},
onLoiReportAction = {},
) {
Box(modifier = Modifier.fillMaxSize().background(Color.LightGray)) {
Text(text = PAGER_CONTENT_TEXT, modifier = Modifier.align(Alignment.Center))
}
Expand All @@ -58,6 +61,7 @@ private fun DataCollectionContentErrorPreview() {
cause = Error("Some error"),
),
onCloseClicked = {},
onLoiReportAction = {},
) {
Box(modifier = Modifier.fillMaxSize().background(Color.LightGray)) {
Text(text = PAGER_CONTENT_TEXT, modifier = Modifier.align(Alignment.Center))
Expand All @@ -83,6 +87,7 @@ private fun DataCollectionContentPreview() {
position = TaskPosition(0, 1, 3),
),
onCloseClicked = {},
onLoiReportAction = {},
) {
Box(modifier = Modifier.fillMaxSize().background(Color.LightGray)) {
Text(text = PAGER_CONTENT_TEXT, modifier = Modifier.align(Alignment.Center))
Expand All @@ -101,15 +106,13 @@ private fun DataCollectionContentCompletePreview() {
DataCollectionUiState.TaskSubmitted(
loiReport =
LoiReport(
surveyName = "Test Survey",
userName = "John Doe",
dateMillis = Clock.System.now().toEpochMilliseconds(),
loiName = "Point A",
geoJson = JsonObject(mapOf()),
submissions = emptyList()
submissionDetails = null,
)
),
onCloseClicked = {},
onLoiReportAction = {},
) {
Box(modifier = Modifier.fillMaxSize().background(Color.LightGray)) {
Text(text = PAGER_CONTENT_TEXT, modifier = Modifier.align(Alignment.Center))
Expand Down
Loading
Loading