diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/configuration/app/ApplicationConfiguration.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/configuration/app/ApplicationConfiguration.kt index 507d185a26..e4dfa850d1 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/configuration/app/ApplicationConfiguration.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/configuration/app/ApplicationConfiguration.kt @@ -42,6 +42,13 @@ data class ApplicationConfiguration( val showLogo: Boolean = true, val taskBackgroundWorkerBatchSize: Int = 500, val eventWorkflows: List<EventWorkflow> = emptyList(), + val settingsScreenMenuOptions: List<SettingsOptions> = + listOf( + SettingsOptions.MANUAL_SYNC, + SettingsOptions.SWITCH_LANGUAGES, + SettingsOptions.RESET_DATA, + SettingsOptions.INSIGHTS, + ), val logGpsLocation: List<LocationLogOptions> = emptyList(), val usePractitionerAssignedLocationOnSync: Boolean = true, // TODO This defaults to scheduling periodic sync, otherwise use sync location ids from @@ -61,3 +68,12 @@ enum class LocationLogOptions { QUESTIONNAIRE, CALCULATE_DISTANCE_RULE_EXECUTOR, } + +enum class SettingsOptions { + MANUAL_SYNC, + OFFLINE_MAPS, + SWITCH_LANGUAGES, + RESET_DATA, + INSIGHTS, + CONTACT_HELP, +} diff --git a/android/engine/src/main/res/values/strings.xml b/android/engine/src/main/res/values/strings.xml index 330bc41845..4571522bdf 100644 --- a/android/engine/src/main/res/values/strings.xml +++ b/android/engine/src/main/res/values/strings.xml @@ -175,7 +175,7 @@ <string name="location">Location</string> <string name="app_version_code">App version code</string> <string name="build_date">Build date</string> - <string name="manufacture">Manufacture</string> + <string name="manufacture">Manufacturer</string> <string name="app_versions">App version</string> <string name="os_version">OS Version</string> <string name="device_date">Date</string> diff --git a/android/quest/.gitignore b/android/quest/.gitignore index 57a22c9c26..8c13f9ec2f 100644 --- a/android/quest/.gitignore +++ b/android/quest/.gitignore @@ -3,3 +3,4 @@ release/ src/*/assets/configs/ src/androidTest/assets/resources.db src/benchmark/assets/resources.db +**/debug/ diff --git a/android/quest/build.gradle.kts b/android/quest/build.gradle.kts index 15d65cc413..cd671f62a5 100644 --- a/android/quest/build.gradle.kts +++ b/android/quest/build.gradle.kts @@ -288,7 +288,7 @@ android { dimension = "apps" applicationIdSuffix = ".gizeir" versionNameSuffix = "-gizeir" - manifestPlaceholders["appLabel"] = "GIZ EIR" + manifestPlaceholders["appLabel"] = "EIR" } create("engage") { diff --git a/android/quest/src/androidTest/java/org/smartregister/fhircore/quest/integration/ui/usersetting/UserSettingScreenTest.kt b/android/quest/src/androidTest/java/org/smartregister/fhircore/quest/integration/ui/usersetting/UserSettingScreenTest.kt index 18b8818dc3..17b7933bd8 100644 --- a/android/quest/src/androidTest/java/org/smartregister/fhircore/quest/integration/ui/usersetting/UserSettingScreenTest.kt +++ b/android/quest/src/androidTest/java/org/smartregister/fhircore/quest/integration/ui/usersetting/UserSettingScreenTest.kt @@ -181,6 +181,10 @@ class UserSettingScreenTest { isShowDatabaseResetConfirmation: Boolean = false, isDebugVariant: Boolean = false, isP2PAvailable: Boolean = false, + showManualSync: Boolean = true, + showAppInsights: Boolean = true, + hasOfflineMaps: Boolean = true, + showContactHelp: Boolean = true, ) { scenario.onActivity { activity -> activity.setContent { @@ -189,17 +193,21 @@ class UserSettingScreenTest { fullname = "Jam Kenya", practitionerLocation = "Gateway Remote Location", username = userName, - allowSwitchingLanguages = allowSwitchingLanguages, selectedLanguage = Locale.ENGLISH.toLanguageTag(), languages = listOf(Language("en", "English"), Language("sw", "Swahili")), - showDatabaseResetConfirmation = isShowDatabaseResetConfirmation, progressBarState = Pair(isShowProgressBar, R.string.resetting_app), isDebugVariant = isDebugVariant, onEvent = {}, mainNavController = rememberNavController(), - allowP2PSync = isP2PAvailable, lastSyncTime = "05:30 PM, Mar 3", showProgressIndicatorFlow = MutableStateFlow(false), + enableManualSync = showManualSync, + allowSwitchingLanguages = allowSwitchingLanguages, + showDatabaseResetConfirmation = isShowDatabaseResetConfirmation, + allowP2PSync = isP2PAvailable, + enableAppInsights = showAppInsights, + showOfflineMaps = hasOfflineMaps, + enableHelpContacts = showContactHelp, ) } diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/usersetting/UserSettingFragment.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/usersetting/UserSettingFragment.kt index e5d1282cbe..4a2ff3c565 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/usersetting/UserSettingFragment.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/usersetting/UserSettingFragment.kt @@ -42,6 +42,7 @@ import javax.inject.Inject import kotlinx.coroutines.launch import org.smartregister.fhircore.engine.BuildConfig import org.smartregister.fhircore.engine.R +import org.smartregister.fhircore.engine.configuration.app.SettingsOptions import org.smartregister.fhircore.engine.domain.model.SnackBarMessageConfig import org.smartregister.fhircore.engine.sync.OnSyncListener import org.smartregister.fhircore.engine.sync.SyncListenerManager @@ -97,19 +98,27 @@ class UserSettingFragment : Fragment(), OnSyncListener { username = userSettingViewModel.retrieveUsername(), practitionerLocation = userSettingViewModel.practitionerLocation(), fullname = userSettingViewModel.retrieveUserInfo()?.name, - allowSwitchingLanguages = userSettingViewModel.allowSwitchingLanguages(), selectedLanguage = userSettingViewModel.loadSelectedLanguage(), - allowP2PSync = userSettingViewModel.enabledDeviceToDeviceSync(), languages = userSettingViewModel.languages, onEvent = userSettingViewModel::onEvent, - showDatabaseResetConfirmation = - userSettingViewModel.showDBResetConfirmationDialog.observeAsState(false).value, progressBarState = userSettingViewModel.progressBarState.observeAsState(Pair(false, 0)).value, isDebugVariant = BuildConfig.DEBUG, mainNavController = findNavController(), lastSyncTime = userSettingViewModel.retrieveLastSyncTimestamp(), showProgressIndicatorFlow = userSettingViewModel.showProgressIndicatorFlow, + enableManualSync = + userSettingViewModel.enableMenuOption(SettingsOptions.MANUAL_SYNC), + allowSwitchingLanguages = userSettingViewModel.allowSwitchingLanguages(), + showDatabaseResetConfirmation = + userSettingViewModel.enableMenuOption(SettingsOptions.RESET_DATA) && + userSettingViewModel.showDBResetConfirmationDialog.observeAsState(false).value, + enableAppInsights = userSettingViewModel.enableMenuOption(SettingsOptions.INSIGHTS), + showOfflineMaps = + userSettingViewModel.enableMenuOption(SettingsOptions.OFFLINE_MAPS), + allowP2PSync = userSettingViewModel.enabledDeviceToDeviceSync(), + enableHelpContacts = + userSettingViewModel.enableMenuOption(SettingsOptions.CONTACT_HELP), ) } } diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/usersetting/UserSettingScreen.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/usersetting/UserSettingScreen.kt index 7efbf366d5..f145fff38b 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/usersetting/UserSettingScreen.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/usersetting/UserSettingScreen.kt @@ -113,18 +113,22 @@ fun UserSettingScreen( username: String?, practitionerLocation: String?, fullname: String?, - allowSwitchingLanguages: Boolean, selectedLanguage: String, languages: List<Language>, - showDatabaseResetConfirmation: Boolean, progressBarState: Pair<Boolean, Int>, isDebugVariant: Boolean = false, onEvent: (UserSettingsEvent) -> Unit, mainNavController: NavController, appVersionPair: Pair<Int, String>? = null, - allowP2PSync: Boolean, lastSyncTime: String?, showProgressIndicatorFlow: MutableStateFlow<Boolean>, + enableManualSync: Boolean, + allowSwitchingLanguages: Boolean, + showDatabaseResetConfirmation: Boolean, + enableAppInsights: Boolean, + showOfflineMaps: Boolean = false, + allowP2PSync: Boolean = false, + enableHelpContacts: Boolean = false, ) { val context = LocalContext.current val (showProgressBar, messageResource) = progressBarState @@ -212,20 +216,25 @@ fun UserSettingScreen( } } Divider(color = DividerColor) - UserSettingRow( - icon = Icons.Rounded.Sync, - text = stringResource(id = R.string.sync), - clickListener = { onEvent(UserSettingsEvent.SyncData(context)) }, - modifier = modifier.testTag(USER_SETTING_ROW_SYNC), - ) - UserSettingRow( - icon = Icons.Rounded.Map, - text = stringResource(id = R.string.offline_map), - clickListener = { onEvent(UserSettingsEvent.OnLaunchOfflineMap(true, context)) }, - modifier = modifier.testTag(USER_SETTING_ROW_OFFLINE_MAP), - canSwitchToScreen = true, - ) + if (enableManualSync) { + UserSettingRow( + icon = Icons.Rounded.Sync, + text = stringResource(id = R.string.sync), + clickListener = { onEvent(UserSettingsEvent.SyncData(context)) }, + modifier = modifier.testTag(USER_SETTING_ROW_SYNC), + ) + } + + if (showOfflineMaps) { + UserSettingRow( + icon = Icons.Rounded.Map, + text = stringResource(id = R.string.offline_map), + clickListener = { onEvent(UserSettingsEvent.OnLaunchOfflineMap(true, context)) }, + modifier = modifier.testTag(USER_SETTING_ROW_OFFLINE_MAP), + canSwitchToScreen = true, + ) + } // Language option if (allowSwitchingLanguages) { @@ -323,23 +332,28 @@ fun UserSettingScreen( ) } - UserSettingRow( - icon = Icons.Rounded.Insights, - text = stringResource(id = R.string.insights), - clickListener = { - onEvent(UserSettingsEvent.ShowInsightsScreen(navController = mainNavController)) - }, - modifier = modifier.testTag(USER_SETTING_ROW_INSIGHTS), - showProgressIndicator = showProgressIndicatorFlow.collectAsState().value, - canSwitchToScreen = true, - ) - UserSettingRow( - icon = Icons.Rounded.Phone, - text = stringResource(id = R.string.contact_help), - clickListener = { onEvent(UserSettingsEvent.ShowContactView(true, context)) }, - modifier = modifier.testTag(USER_SETTING_ROW_CONTACT_HELP), - canSwitchToScreen = true, - ) + if (enableAppInsights) { + UserSettingRow( + icon = Icons.Rounded.Insights, + text = stringResource(id = R.string.insights), + clickListener = { + onEvent(UserSettingsEvent.ShowInsightsScreen(navController = mainNavController)) + }, + modifier = modifier.testTag(USER_SETTING_ROW_INSIGHTS), + showProgressIndicator = showProgressIndicatorFlow.collectAsState().value, + canSwitchToScreen = true, + ) + } + + if (enableHelpContacts) { + UserSettingRow( + icon = Icons.Rounded.Phone, + text = stringResource(id = R.string.contact_help), + clickListener = { onEvent(UserSettingsEvent.ShowContactView(true, context)) }, + modifier = modifier.testTag(USER_SETTING_ROW_CONTACT_HELP), + canSwitchToScreen = true, + ) + } UserSettingRow( icon = Icons.Rounded.Logout, @@ -484,17 +498,21 @@ fun UserSettingPreview() { username = "Jam", fullname = "Jam Kenya", practitionerLocation = "Gateway Remote Location", - allowSwitchingLanguages = true, selectedLanguage = java.util.Locale.ENGLISH.toLanguageTag(), languages = listOf(Language("en", "English"), Language("sw", "Swahili")), - showDatabaseResetConfirmation = false, progressBarState = Pair(false, R.string.resetting_app), isDebugVariant = true, onEvent = {}, mainNavController = rememberNavController(), appVersionPair = Pair(1, "1.0.1"), - allowP2PSync = true, lastSyncTime = "05:30 PM, Mar 3", showProgressIndicatorFlow = MutableStateFlow(false), + enableManualSync = true, + allowSwitchingLanguages = true, + showDatabaseResetConfirmation = false, + enableAppInsights = true, + showOfflineMaps = true, + allowP2PSync = true, + enableHelpContacts = true, ) } diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/usersetting/UserSettingViewModel.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/usersetting/UserSettingViewModel.kt index dae2781b59..286813b7f4 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/usersetting/UserSettingViewModel.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/usersetting/UserSettingViewModel.kt @@ -35,6 +35,7 @@ import org.smartregister.fhircore.engine.R import org.smartregister.fhircore.engine.configuration.ConfigType import org.smartregister.fhircore.engine.configuration.ConfigurationRegistry import org.smartregister.fhircore.engine.configuration.app.ApplicationConfiguration +import org.smartregister.fhircore.engine.configuration.app.SettingsOptions import org.smartregister.fhircore.engine.data.remote.model.response.UserInfo import org.smartregister.fhircore.engine.domain.model.SnackBarMessageConfig import org.smartregister.fhircore.engine.sync.SyncBroadcaster @@ -104,7 +105,11 @@ constructor( fun retrieveLastSyncTimestamp(): String? = sharedPreferencesHelper.read(SharedPreferenceKey.LAST_SYNC_TIMESTAMP.name, null) - fun allowSwitchingLanguages() = languages.size > 1 + fun enableMenuOption(settingOption: SettingsOptions) = + applicationConfiguration.settingsScreenMenuOptions.contains(settingOption) + + fun allowSwitchingLanguages() = + enableMenuOption(SettingsOptions.SWITCH_LANGUAGES) && languages.size > 1 fun loadSelectedLanguage(): String = Locale.forLanguageTag( diff --git a/android/quest/src/test/java/org/smartregister/fhircore/quest/ui/usersetting/UserSettingViewModelTest.kt b/android/quest/src/test/java/org/smartregister/fhircore/quest/ui/usersetting/UserSettingViewModelTest.kt index 5fb5ebd882..f375ab5fcf 100644 --- a/android/quest/src/test/java/org/smartregister/fhircore/quest/ui/usersetting/UserSettingViewModelTest.kt +++ b/android/quest/src/test/java/org/smartregister/fhircore/quest/ui/usersetting/UserSettingViewModelTest.kt @@ -48,6 +48,7 @@ import org.robolectric.Shadows import org.robolectric.shadows.ShadowLooper import org.smartregister.fhircore.engine.R import org.smartregister.fhircore.engine.configuration.app.ConfigService +import org.smartregister.fhircore.engine.configuration.app.SettingsOptions import org.smartregister.fhircore.engine.data.remote.fhir.resource.FhirResourceDataSource import org.smartregister.fhircore.engine.data.remote.fhir.resource.FhirResourceService import org.smartregister.fhircore.engine.domain.model.Language @@ -180,25 +181,39 @@ class UserSettingViewModelTest : RobolectricTest() { } @Test - fun allowSwitchingLanguagesShouldReturnTrueWhenMultipleLanguagesAreConfigured() { + fun allowSwitchingLanguagesShouldReturnFalseWhenSwitchLanguagesOptionIsNotSetAndMultipleLanguagesAreConfigured() { val languages = listOf(Language("es", "Spanish"), Language("en", "English")) userSettingViewModel = spyk(userSettingViewModel) + every { userSettingViewModel.enableMenuOption(SettingsOptions.SWITCH_LANGUAGES) } returns false every { userSettingViewModel.languages } returns languages - Assert.assertTrue(userSettingViewModel.allowSwitchingLanguages()) + Assert.assertFalse(userSettingViewModel.allowSwitchingLanguages()) Shadows.shadowOf(Looper.getMainLooper()).idle() } @Test - fun allowSwitchingLanguagesShouldReturnFalseWhenConfigurationIsFalse() { - val languages = listOf(Language("es", "Spanish")) + fun allowSwitchingLanguagesShouldReturnTrueWhenSwitchLanguagesOptionIsSetAndMultipleLanguagesAreConfigured() { + val languages = listOf(Language("es", "Spanish"), Language("en", "English")) userSettingViewModel = spyk(userSettingViewModel) + every { userSettingViewModel.enableMenuOption(SettingsOptions.SWITCH_LANGUAGES) } returns true every { userSettingViewModel.languages } returns languages + + Assert.assertTrue(userSettingViewModel.allowSwitchingLanguages()) Shadows.shadowOf(Looper.getMainLooper()).idle() + } + + @Test + fun allowSwitchingLanguagesShouldReturnFalseWhenSwitchLanguagesOptionIsSetAndOnlyOneLanguageIsConfigured() { + val languages = listOf(Language("en", "English")) + userSettingViewModel = spyk(userSettingViewModel) + + every { userSettingViewModel.enableMenuOption(SettingsOptions.SWITCH_LANGUAGES) } returns true + every { userSettingViewModel.languages } returns languages Assert.assertFalse(userSettingViewModel.allowSwitchingLanguages()) + Shadows.shadowOf(Looper.getMainLooper()).idle() } @Test diff --git a/docs/engineering/android-app/configuring/config-types/application.mdx b/docs/engineering/android-app/configuring/config-types/application.mdx index 2a8a8e0c62..dea00db12d 100644 --- a/docs/engineering/android-app/configuring/config-types/application.mdx +++ b/docs/engineering/android-app/configuring/config-types/application.mdx @@ -84,4 +84,6 @@ The `logGpsLocation` config takes in a list of `LocationLogOptions` to toggle wh `showLogo` | Toggle whether to show the logo | Yes | `true` | `taskBackgroundWorkerBatchSize` | Batch size of tasks to be fetched from the server | Yes | `500` | `eventWorkflows` | A list of `EventWorkflow`s | Yes | `emptyList()` | -`logGpsLocation` | A list of `LocationLogOptions` to toggle whether to capture GPS coordinates | Yes | emptyList() | \ No newline at end of file +`settingsScreenMenuOptions` | A list of `SettingsOptions`s that defines menu options to be displayed on the `Settings` screen | Yes | `listOf(SettingsOptions.MANUAL_SYNC, SettingsOptions.SWITCH_LANGUAGES, SettingsOptions.RESET_DATA, SettingsOptions.INSIGHTS,)` | +`logGpsLocation` | A list of `LocationLogOptions` to toggle whether to capture GPS coordinates | Yes | emptyList() | +`usePractitionerAssignedLocationOnSync` | If `true`, default to using logged in practitioner's location | Yes | `true` |