Skip to content
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
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.simprints.feature.dashboard.settings.syncinfo

data class SyncInfo(
import com.simprints.feature.dashboard.settings.syncinfo.modulecount.ModuleCount

internal data class SyncInfo(
val isLoggedIn: Boolean = true,
val isConfigurationLoadingProgressBarVisible: Boolean = false,
val isLoginPromptSectionVisible: Boolean = false,
Expand All @@ -10,7 +12,7 @@ data class SyncInfo(
val syncInfoSectionModules: SyncInfoSectionModules = SyncInfoSectionModules(),
)

data class SyncInfoSectionRecords(
internal data class SyncInfoSectionRecords(
// counters
val counterTotalRecords: String = "",
val counterRecordsToUpload: String = "",
Expand Down Expand Up @@ -40,13 +42,13 @@ data class SyncInfoSectionRecords(
val footerLastSyncMinutesAgo: String = "",
)

data class SyncInfoError(
internal data class SyncInfoError(
val isBackendMaintenance: Boolean = false,
val backendMaintenanceEstimatedOutage: Long = -1,
val isTooManyRequests: Boolean = false,
)

data class SyncInfoSectionImages(
internal data class SyncInfoSectionImages(
// counters
val counterImagesToUpload: String = "",
// instructions
Expand All @@ -62,31 +64,25 @@ data class SyncInfoSectionImages(
val footerLastSyncMinutesAgo: String = "",
)

data class SyncInfoProgress(
internal data class SyncInfoProgress(
val progressParts: List<SyncInfoProgressPart> = listOf(),
val progressBarPercentage: Int = 0,
)

data class SyncInfoProgressPart(
internal data class SyncInfoProgressPart(
val isPending: Boolean = true,
val isDone: Boolean = false,
val areNumbersVisible: Boolean = false,
val currentNumber: Int = 0,
val totalNumber: Int = 0,
)

data class SyncInfoSectionModules(
internal data class SyncInfoSectionModules(
val isSectionAvailable: Boolean = false,
val moduleCounts: List<SyncInfoModuleCount> = emptyList(),
)

data class SyncInfoModuleCount(
val isTotal: Boolean = false,
val name: String,
val count: String = "",
val moduleCounts: List<ModuleCount> = emptyList(),
)

enum class LogoutActionReason {
internal enum class LogoutActionReason {
USER_ACTION,
PROJECT_ENDING_OR_DEVICE_COMPROMISED,
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import com.simprints.feature.dashboard.R
import com.simprints.feature.dashboard.databinding.FragmentSyncInfoBinding
import com.simprints.feature.dashboard.requestlogin.LogoutReason
import com.simprints.feature.dashboard.requestlogin.RequestLoginFragmentArgs
import com.simprints.feature.dashboard.settings.syncinfo.modulecount.ModuleCount
import com.simprints.feature.dashboard.settings.syncinfo.modulecount.ModuleCountAdapter
import com.simprints.feature.dashboard.view.ConfigurableSyncInfoFragmentContainer
import com.simprints.feature.login.LoginContract
Expand Down Expand Up @@ -340,24 +339,13 @@ internal class SyncInfoFragment : Fragment(R.layout.fragment_sync_info) {
binding.layoutModuleSelection.isGone = !isModuleSectionVisible
binding.selectedModulesView.isGone = !config.isSyncInfoModuleListVisible

val moduleCountsForAdapter = modules.moduleCounts.map { syncInfoModuleCount ->
ModuleCount(
name = if (syncInfoModuleCount.isTotal) {
getString(IDR.string.sync_info_total_records)
} else {
syncInfoModuleCount.name
},
count = syncInfoModuleCount.count.toIntOrNull() ?: 0,
)
}

moduleCountAdapter.submitList(moduleCountsForAdapter)
moduleCountAdapter.submitList(modules.moduleCounts)

// RecyclerView height fix (wrong height may be caused by ConstraintLayout in parent views)
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
val itemHeight = resources.getDimensionPixelSize(R.dimen.module_item_height)
val itemCount = moduleCountsForAdapter.size.coerceAtMost(MAX_MODULE_LIST_HEIGHT_ITEMS)
val itemCount = modules.moduleCounts.size.coerceAtMost(MAX_MODULE_LIST_HEIGHT_ITEMS)
binding.selectedModulesView.apply {
layoutParams = layoutParams.apply {
height = itemHeight * itemCount
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.simprints.feature.dashboard.R
import com.simprints.infra.resources.R as IDR

internal class ModuleCountViewHolder(
itemView: View,
Expand All @@ -18,14 +19,13 @@ internal class ModuleCountViewHolder(
moduleCount: ModuleCount,
isFirstElementForTotalCount: Boolean,
) {
moduleItemIcon.setImageResource(
if (isFirstElementForTotalCount) {
R.drawable.ic_global
} else {
R.drawable.ic_module
},
)
moduleNameText.text = moduleCount.name
if (isFirstElementForTotalCount) {
moduleItemIcon.setImageResource(R.drawable.ic_global)
moduleNameText.setText(IDR.string.sync_info_total_records)
} else {
moduleItemIcon.setImageResource(R.drawable.ic_module)
moduleNameText.text = moduleCount.name
}
moduleCountText.text = moduleCount.count.toString()

if (isFirstElementForTotalCount) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.simprints.feature.dashboard.settings.syncinfo.usecase

import com.simprints.core.domain.tokenization.TokenizableString
import com.simprints.feature.dashboard.settings.syncinfo.modulecount.ModuleCount
import com.simprints.infra.config.store.models.ProjectConfiguration
import com.simprints.infra.config.store.models.ProjectState
import com.simprints.infra.config.store.models.TokenKeyType
import com.simprints.infra.config.store.tokenization.TokenizationProcessor
import com.simprints.infra.config.sync.ConfigManager
import com.simprints.infra.enrolment.records.repository.EnrolmentRecordRepository
import com.simprints.infra.enrolment.records.repository.domain.models.SubjectQuery
import kotlinx.coroutines.flow.combine
import javax.inject.Inject

internal class ObserveConfigurationChangesUseCase @Inject constructor(
private val configManager: ConfigManager,
private val tokenizationProcessor: TokenizationProcessor,
private val enrolmentRecordRepository: EnrolmentRecordRepository,
) {
operator fun invoke() = combine(
configManager.observeIsProjectRefreshing(),
configManager.observeProjectConfiguration(),
configManager.observeDeviceConfiguration(),
) { isRefreshing, projectConfig, deviceConfig ->
val project = configManager.getProject()

val moduleCounts = if (project != null) {
deviceConfig.selectedModules.map { moduleName ->
ModuleCount(
name = when (moduleName) {
is TokenizableString.Raw -> moduleName

is TokenizableString.Tokenized -> tokenizationProcessor.decrypt(
encrypted = moduleName,
tokenKeyType = TokenKeyType.ModuleId,
project,
)
}.value,
count = enrolmentRecordRepository.count(
SubjectQuery(projectId = project.id, moduleId = moduleName),
),
)
}
} else {
emptyList()
}

ConfigurationState(
isRefreshing = isRefreshing,
isProjectRunning = project?.state == ProjectState.RUNNING,
selectedModules = moduleCounts,
projectConfig = projectConfig,
)
}
}

internal data class ConfigurationState(
val isRefreshing: Boolean,
val isProjectRunning: Boolean,
val selectedModules: List<ModuleCount>,
val projectConfig: ProjectConfiguration,
)
Loading