diff --git a/.idea/AndroidProjectSystem.xml b/.idea/AndroidProjectSystem.xml
new file mode 100644
index 0000000..4a53bee
--- /dev/null
+++ b/.idea/AndroidProjectSystem.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/appInsightsSettings.xml b/.idea/appInsightsSettings.xml
index 371f2e2..b2b6f45 100644
--- a/.idea/appInsightsSettings.xml
+++ b/.idea/appInsightsSettings.xml
@@ -3,6 +3,20 @@
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index efacb99..639c779 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -6,14 +6,13 @@
-
+
-
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index 005afb3..f0c6ad0 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -40,6 +40,9 @@
+
+
+
diff --git a/.idea/misc.xml b/.idea/misc.xml
index b2c751a..f7608ed 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,9 +1,4 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/.kotlin/errors/errors-1738346278539.log b/.kotlin/errors/errors-1738346278539.log
new file mode 100644
index 0000000..38b1cc9
--- /dev/null
+++ b/.kotlin/errors/errors-1738346278539.log
@@ -0,0 +1,4 @@
+kotlin version: 2.0.20-RC
+error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 0. The daemon process output:
+ 1. Kotlin compile daemon is ready
+
diff --git a/.kotlin/errors/errors-1739362815060.log b/.kotlin/errors/errors-1739362815060.log
new file mode 100644
index 0000000..38b1cc9
--- /dev/null
+++ b/.kotlin/errors/errors-1739362815060.log
@@ -0,0 +1,4 @@
+kotlin version: 2.0.20-RC
+error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 0. The daemon process output:
+ 1. Kotlin compile daemon is ready
+
diff --git a/.kotlin/errors/errors-1749473483135.log b/.kotlin/errors/errors-1749473483135.log
new file mode 100644
index 0000000..38b1cc9
--- /dev/null
+++ b/.kotlin/errors/errors-1749473483135.log
@@ -0,0 +1,4 @@
+kotlin version: 2.0.20-RC
+error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 0. The daemon process output:
+ 1. Kotlin compile daemon is ready
+
diff --git a/app/build.gradle b/app/build.gradle
index 306e11c..3244764 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -11,6 +11,8 @@ plugins {
def googleMapsApiKey = System.getenv("GOOGLE_MAPS_API_KEY") ?: ""
def baseUrl = System.getenv("BASE_URL") ?: ""
+def userGuideUrl = System.getenv("USER_GUIDE_URL") ?: ""
+def dataPrivacyUrl = System.getenv("DATA_PRIVACY_URL") ?: ""
android {
namespace 'org.technoserve.farmcollector'
@@ -20,14 +22,16 @@ android {
applicationId "org.technoserve.farmcollector"
minSdk 21
targetSdk 35
- versionCode 53
- versionName "2.39"
+ versionCode 73
+ versionName "2.51"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary true
}
buildConfigField "String", "GOOGLE_MAPS_API_KEY", "\"${googleMapsApiKey}\""
buildConfigField "String", "BASE_URL", "\"${baseUrl}\""
+ buildConfigField "String", "USER_GUIDE_URL", "\"${userGuideUrl}\""
+ buildConfigField "String", "DATA_PRIVACY_URL","\"${dataPrivacyUrl}\""
}
buildTypes {
@@ -51,15 +55,57 @@ android {
}
}
+ def debugUserGuideUrl = project.rootProject.file("local.properties").with { propertiesFile ->
+ if (propertiesFile.exists()) {
+ def properties = new Properties()
+ properties.load(propertiesFile.newInputStream())
+ properties.getProperty("USER_GUIDE_URL", "default_debug_user_guide_url")
+ } else {
+ "default_debug_user_guide_url"
+ }
+ }
+
+ def releaseUserGuideUrl = project.rootProject.file("local.properties").with { propertiesFile ->
+ if (propertiesFile.exists()) {
+ def properties = new Properties()
+ properties.load(propertiesFile.newInputStream())
+ properties.getProperty("USER_GUIDE_URL", "default_release_user_guide_url")
+ } else {
+ "default_release_user_guide_url"
+ }
+ }
+ def debugDataPrivacyUrl = project.rootProject.file("local.properties").with { propertiesFile ->
+ if (propertiesFile.exists()) {
+ def properties = new Properties()
+ properties.load(propertiesFile.newInputStream())
+ properties.getProperty("DATA_PRIVACY_URL", "default_data_privacy_url")
+ } else {
+ "default_data_privacy_url"
+ }
+ }
+ def releaseDataPrivacyUrl = project.rootProject.file("local.properties").with { propertiesFile ->
+ if (propertiesFile.exists()) {
+ def properties = new Properties()
+ properties.load(propertiesFile.newInputStream())
+ properties.getProperty("DATA_PRIVACY_URL", "default_data_privacy_url")
+ } else {
+ "default_data_privacy_url"
+ }
+ }
+
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard'
buildConfigField "String", "BASE_URL", "\"$debugBaseUrl\""
+ buildConfigField "String", "USER_GUIDE_URL", "\"$debugUserGuideUrl\""
+ buildConfigField "String", "DATA_PRIVACY_URL", "\"$debugDataPrivacyUrl\""
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
buildConfigField "String", "BASE_URL", "\"$releaseBaseUrl\""
+ buildConfigField "String", "USER_GUIDE_URL", "\"$releaseUserGuideUrl\""
+ buildConfigField "String", "DATA_PRIVACY_URL", "\"$releaseDataPrivacyUrl\""
}
}
@@ -98,11 +144,6 @@ android {
testOptions {
unitTests {
includeAndroidResources = true
-// all {
-// systemProperty 'robolectric.enabledSdks', '33'
-// systemProperty 'robolectric.build.model', 'DEVICE'
-// environment 'BUILD_FINGERPRINT', 'foo'
-// }
}
}
@@ -130,11 +171,11 @@ dependencies {
implementation("androidx.compose.material3:material3:1.3.1")
implementation("androidx.compose.material3:material3-window-size-class:1.3.1")
implementation 'com.google.android.gms:play-services-ads-identifier:18.1.0'
-// implementation 'androidx.work:work-runtime-ktx:2.10.0'
implementation 'androidx.work:work-runtime-ktx:2.9.0'
- // implementation 'androidx.work:work-runtime:2.8.0'
+ implementation "com.google.accompanist:accompanist-systemuicontroller:0.32.0"
+
// camera dependencies
implementation 'androidx.camera:camera-core:1.4.0'
@@ -212,39 +253,36 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:2.0.20-RC"
-
+ implementation("androidx.datastore:datastore-preferences:1.0.0")
// Testing Dependencies
implementation 'androidx.navigation:navigation-testing:2.4.0-alpha04'
implementation 'androidx.test.ext:junit-ktx:1.2.1'
+ implementation 'com.jakewharton.timber:timber:5.0.1'
+
testImplementation "androidx.test:core:1.5.0"
testImplementation "org.mockito:mockito-core:5.7.0"
testImplementation "org.mockito.kotlin:mockito-kotlin:5.3.1"
testImplementation "io.mockk:mockk:1.13.7"
- // testImplementation "org.robolectric:robolectric:4.10.3"
testImplementation 'com.google.dagger:hilt-android-testing:2.48'
testImplementation 'androidx.compose.ui:ui-test-junit4-android:1.7.5'
testImplementation 'androidx.arch.core:core-testing:2.2.0'
testImplementation "com.google.truth:truth:1.1.3"
testImplementation "io.mockk:mockk:1.13.7"
testImplementation "io.mockk:mockk-android:1.13.5"
- //testImplementation "org.robolectric:robolectric:4.9"
testImplementation("androidx.work:work-testing:2.8.1")
// testImplementation("junit:junit:4.13.2")
testImplementation("org.robolectric:robolectric:4.13")
-
-
// testImplementation "org.robolectric:robolectric:4.11.1"
testImplementation "androidx.test:core:1.5.0"
testImplementation "androidx.test.ext:junit:1.1.5"
testImplementation "androidx.compose.ui:ui-test-junit4:1.5.4"
-
androidTestImplementation "androidx.work:work-testing:2.7.1"
androidTestImplementation "com.google.truth:truth:1.1.3"
androidTestImplementation "androidx.work:work-testing:2.7.1"
diff --git a/app/release/app-release.aab b/app/release/app-release.aab
index 665ad7e..5f5362e 100644
Binary files a/app/release/app-release.aab and b/app/release/app-release.aab differ
diff --git a/app/src/androidTest/java/org/technoserve/farmcollector/utils/LanguageSelectorKtTest.kt b/app/src/androidTest/java/org/technoserve/farmcollector/utils/LanguageSelectorKtTest.kt
deleted file mode 100644
index 2459d92..0000000
--- a/app/src/androidTest/java/org/technoserve/farmcollector/utils/LanguageSelectorKtTest.kt
+++ /dev/null
@@ -1,119 +0,0 @@
-package org.technoserve.farmcollector.utils
-
-import android.annotation.SuppressLint
-import android.content.Context
-import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.compose.ui.test.onNodeWithText
-import androidx.compose.ui.test.performClick
-import androidx.lifecycle.ViewModel
-import io.mockk.Runs
-import io.mockk.every
-import io.mockk.just
-import io.mockk.mockk
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.StateFlow
-import org.junit.Rule
-import org.junit.Test
-import org.mockito.Mockito.verify
-import org.technoserve.farmcollector.ui.screens.settings.LanguageSelector
-import org.technoserve.farmcollector.viewmodels.LanguageViewModel
-
-/*
-
-// Mock Language class
-data class Language(val displayName: String)
-
-// Mock ViewModel
-class LanguageViewModel : ViewModel() {
- private val _currentLanguage = MutableStateFlow(
- org.technoserve.farmcollector.database.models.Language(
- "English"
- )
- )
- val currentLanguage: StateFlow get() = _currentLanguage
-
- fun selectLanguage(language: Language, context: Context) {
- _currentLanguage.value = language
- }
-}
-
-
-class LanguageSelectorKtTest{
- @get:Rule
- val composeTestRule = createComposeRule()
-
- private val mockContext = mockk(relaxed = true)
-
- @Test
- fun languageSelector_displaysCurrentLanguage() {
- val mockViewModel = mockk(relaxed = true)
- val languages = listOf(
- org.technoserve.farmcollector.database.models.Language("English"),
- org.technoserve.farmcollector.database.models.Language("French")
- )
- val currentLanguage = MutableStateFlow(languages[0]) // English
-
- every { mockViewModel.currentLanguage } returns currentLanguage
-
- composeTestRule.setContent {
- LanguageSelector(viewModel = mockViewModel, languages = languages)
- }
-
- // Assert the current language is displayed
- composeTestRule.onNodeWithText("English").assertExists()
- }
-
- @Test
- fun languageSelector_opensDropdownOnClick() {
- val mockViewModel = mockk(relaxed = true)
- val languages = listOf(
- org.technoserve.farmcollector.database.models.Language("English"),
- org.technoserve.farmcollector.database.models.Language("French")
- )
- val currentLanguage = MutableStateFlow(languages[0]) // English
-
- every { mockViewModel.currentLanguage } returns currentLanguage
-
- composeTestRule.setContent {
- LanguageSelector(viewModel = mockViewModel, languages = languages)
- }
-
- // Click on the row to expand the dropdown menu
- composeTestRule.onNodeWithText("English").performClick()
-
- // Assert that the dropdown is expanded and displays the available languages
- composeTestRule.onNodeWithText("French").assertExists()
- }
-
- @SuppressLint("CheckResult")
- @Test
- fun languageSelector_selectsLanguageOnClick() {
- val mockViewModel = mockk(relaxed = true)
- val languages = listOf(
- org.technoserve.farmcollector.database.models.Language("English"),
- org.technoserve.farmcollector.database.models.Language("French")
- )
- val currentLanguage = MutableStateFlow(languages[0]) // English
-
- every { mockViewModel.currentLanguage } returns currentLanguage
- every { mockViewModel.selectLanguage(any(), any()) } just Runs
-
- composeTestRule.setContent {
- LanguageSelector(viewModel = mockViewModel, languages = languages)
- }
-
- // Expand the dropdown
- composeTestRule.onNodeWithText("English").performClick()
-
- // Select the "French" option
- composeTestRule.onNodeWithText("French").performClick()
-
- // Verify that selectLanguage was called with the correct language
- verify { mockViewModel.selectLanguage(
- org.technoserve.farmcollector.database.models.Language(
- "French"
- ), mockContext) }
- }
-}
-
- */
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 5f5af76..8fd9e15 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,14 +7,18 @@
android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"
tools:ignore="ProtectedPermissions" />
-
-
+
+
+
@@ -39,7 +43,7 @@
android:networkSecurityConfig="@xml/network_security_config"
tools:targetApi="31">
+
+
+
+
+ Plot Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Loading map...
+
+
+
+