From 4ddfac3e6dc25419d42a873b88c822fa4a3ff41f Mon Sep 17 00:00:00 2001 From: "muindi.stephen" Date: Fri, 19 Jul 2024 17:33:06 +0300 Subject: [PATCH 1/6] Added LocalFarmCycle: Data class --- app/build.gradle | 10 +- .../smartmkulima/adapter/GapAdapter.kt | 4 + .../data/remote/GAPsAPiService.kt | 4 + .../data/repositories/FarmCycleRepository.kt | 27 ++++ .../smartmkulima/data/room/AppDatabase.kt | 12 +- .../steve_md/smartmkulima/data/room/GAPDao.kt | 18 +++ .../data/room/LocalFarmCycleDao.kt | 4 + .../data/room/converters/GAPConverters.kt | 21 +++ .../converters/LocalFarmCycleConverter.kt | 2 + .../smartmkulima/di/DatabaseModule.kt | 7 + .../smartmkulima/di/RepositoryModule.kt | 9 ++ .../com/steve_md/smartmkulima/model/Cycle.kt | 8 +- .../com/steve_md/smartmkulima/model/GAP.kt | 11 +- .../smartmkulima/model/LocalFarmCycle.kt | 2 + .../fragments/main/HomeDashboardFragment.kt | 7 +- .../main/MonitorFarmConditionFragment.kt | 4 +- .../crop_cycle/AutoCreateCropCycleFragment.kt | 22 ++- .../crop_cycle/CropCycleTasksListFragment.kt | 11 +- .../others/gap/ViewAllGAPsragment.kt | 106 ++++++++++++ .../others/gap/ViewDetailsGAPTasksFragment.kt | 65 ++++++++ .../smartmkulima/utils/ExtensionFunctions.kt | 64 ++++++++ .../smartmkulima/viewmodel/MainViewModel.kt | 19 ++- .../res/layout/fragment_crop_cycle_list.xml | 30 +++- .../res/layout/fragment_home_dashboard.xml | 13 +- .../fragment_view_all_g_a_psragment.xml | 35 ++++ .../fragment_view_details_g_a_p_tasks.xml | 153 ++++++++++++++++++ .../main/res/navigation/navigation_graph.xml | 21 +++ app/src/main/res/values/strings.xml | 1 + 28 files changed, 666 insertions(+), 24 deletions(-) create mode 100644 app/src/main/java/com/steve_md/smartmkulima/data/repositories/FarmCycleRepository.kt create mode 100644 app/src/main/java/com/steve_md/smartmkulima/data/room/GAPDao.kt create mode 100644 app/src/main/java/com/steve_md/smartmkulima/data/room/LocalFarmCycleDao.kt create mode 100644 app/src/main/java/com/steve_md/smartmkulima/data/room/converters/GAPConverters.kt create mode 100644 app/src/main/java/com/steve_md/smartmkulima/data/room/converters/LocalFarmCycleConverter.kt create mode 100644 app/src/main/java/com/steve_md/smartmkulima/model/LocalFarmCycle.kt create mode 100644 app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/gap/ViewAllGAPsragment.kt create mode 100644 app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/gap/ViewDetailsGAPTasksFragment.kt create mode 100644 app/src/main/res/layout/fragment_view_all_g_a_psragment.xml create mode 100644 app/src/main/res/layout/fragment_view_details_g_a_p_tasks.xml diff --git a/app/build.gradle b/app/build.gradle index d797dc5c..43d2dfa3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -76,8 +76,8 @@ dependencies { // Testing testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test.ext:junit:1.1.5' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' + androidTestImplementation 'androidx.test.ext:junit:1.2.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' // Navigation Components implementation("androidx.navigation:navigation-fragment-ktx:2.7.7") @@ -85,10 +85,10 @@ dependencies { // Alternatively - just LiveData - implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.8.2") + implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.8.3") // Alternatively - just ViewModel - implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.2") + implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.3") // Dagger - Hilt implementation 'com.google.dagger:hilt-android:2.50' @@ -123,7 +123,7 @@ dependencies { // Maps - Dependency - implementation 'com.google.android.gms:play-services-maps:18.2.0' + implementation 'com.google.android.gms:play-services-maps:19.0.0' implementation 'com.google.android.gms:play-services-location:21.3.0' // Lottie Animation diff --git a/app/src/main/java/com/steve_md/smartmkulima/adapter/GapAdapter.kt b/app/src/main/java/com/steve_md/smartmkulima/adapter/GapAdapter.kt index 2b5dd0e6..a0c5b1b6 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/adapter/GapAdapter.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/adapter/GapAdapter.kt @@ -10,6 +10,10 @@ import com.bumptech.glide.Glide import com.steve_md.smartmkulima.databinding.HomeGapRowBinding import com.steve_md.smartmkulima.model.GAP +/** + * Bind fetched GAPS to the Ui (Recycler View) + * - In order to display a list of available GAPs to the RecyclerView Ui + */ class GapAdapter(private val onClickListener: OnClickListener) : ListAdapter(TaskDiffUtil) { diff --git a/app/src/main/java/com/steve_md/smartmkulima/data/remote/GAPsAPiService.kt b/app/src/main/java/com/steve_md/smartmkulima/data/remote/GAPsAPiService.kt index 1503c019..34d6cba9 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/data/remote/GAPsAPiService.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/data/remote/GAPsAPiService.kt @@ -4,6 +4,10 @@ import com.steve_md.smartmkulima.model.GAP import retrofit2.Call import retrofit2.http.GET +/** + * Fetch a list of + * Good Agricultural Practices from the API + */ interface GAPsAPiService { @GET("goodagriculturalpractices") diff --git a/app/src/main/java/com/steve_md/smartmkulima/data/repositories/FarmCycleRepository.kt b/app/src/main/java/com/steve_md/smartmkulima/data/repositories/FarmCycleRepository.kt new file mode 100644 index 00000000..89ea55c8 --- /dev/null +++ b/app/src/main/java/com/steve_md/smartmkulima/data/repositories/FarmCycleRepository.kt @@ -0,0 +1,27 @@ +package com.steve_md.smartmkulima.data.repositories + +import com.steve_md.smartmkulima.data.room.AppDatabase +import com.steve_md.smartmkulima.data.room.GAPDao +import com.steve_md.smartmkulima.model.Cycle +import com.steve_md.smartmkulima.model.GAP +import com.steve_md.smartmkulima.utils.apiRequestByResource +import com.steve_md.smartmkulima.utils.safeCall +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +/** + * Farm cycles repository + * Manual creating of repositories + */ +class FarmCycleRepository @Inject constructor( + database: AppDatabase +) { + private val gapDao: GAPDao = database.gapDao() + + suspend fun insertCycle(cycle: Cycle) = apiRequestByResource { + gapDao.insertGAP(cycle) + } + + val allCycles : Flow> = gapDao.getAllCycle() + +} \ No newline at end of file diff --git a/app/src/main/java/com/steve_md/smartmkulima/data/room/AppDatabase.kt b/app/src/main/java/com/steve_md/smartmkulima/data/room/AppDatabase.kt index 36f8d289..b0c1ac85 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/data/room/AppDatabase.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/data/room/AppDatabase.kt @@ -2,16 +2,26 @@ package com.steve_md.smartmkulima.data.room import androidx.room.Database import androidx.room.RoomDatabase +import androidx.room.TypeConverters +import com.steve_md.smartmkulima.data.room.converters.Converters +import com.steve_md.smartmkulima.model.Cycle import com.steve_md.smartmkulima.model.FarmProduce +import com.steve_md.smartmkulima.model.GAP +import com.steve_md.smartmkulima.model.GAPtask +import com.steve_md.smartmkulima.model.Task +import com.steve_md.smartmkulima.model.Tasks import com.steve_md.smartmkulima.model.Transaction -@Database(entities = [Transaction::class,FarmProduce::class], version = 3, exportSchema = false) +@TypeConverters(Converters::class) +@Database(entities = [Transaction::class,FarmProduce::class, Cycle::class, Tasks::class], version = 3, exportSchema = false) abstract class AppDatabase : RoomDatabase() { abstract fun transactionDao(): TransactionDao abstract fun farmProduceDao() : FarmProduceDao + abstract fun gapDao(): GAPDao + /** * Implement singleton pattern in room to prevent * multiple instances of room database opening at the sametime diff --git a/app/src/main/java/com/steve_md/smartmkulima/data/room/GAPDao.kt b/app/src/main/java/com/steve_md/smartmkulima/data/room/GAPDao.kt new file mode 100644 index 00000000..9d0b42bd --- /dev/null +++ b/app/src/main/java/com/steve_md/smartmkulima/data/room/GAPDao.kt @@ -0,0 +1,18 @@ +package com.steve_md.smartmkulima.data.room + +import androidx.room.* +import com.steve_md.smartmkulima.model.Cycle +import com.steve_md.smartmkulima.model.GAP +import kotlinx.coroutines.flow.Flow + +@Dao +interface GAPDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertGAP(cycle: Cycle) + + @Query("SELECT * FROM cycle") + fun getAllCycle(): Flow> + + @Delete + suspend fun deleteGAP(cycle: Cycle) +} diff --git a/app/src/main/java/com/steve_md/smartmkulima/data/room/LocalFarmCycleDao.kt b/app/src/main/java/com/steve_md/smartmkulima/data/room/LocalFarmCycleDao.kt new file mode 100644 index 00000000..ce7cc046 --- /dev/null +++ b/app/src/main/java/com/steve_md/smartmkulima/data/room/LocalFarmCycleDao.kt @@ -0,0 +1,4 @@ +package com.steve_md.smartmkulima.data.room + +interface LocalFarmCycleDao { +} \ No newline at end of file diff --git a/app/src/main/java/com/steve_md/smartmkulima/data/room/converters/GAPConverters.kt b/app/src/main/java/com/steve_md/smartmkulima/data/room/converters/GAPConverters.kt new file mode 100644 index 00000000..d6128903 --- /dev/null +++ b/app/src/main/java/com/steve_md/smartmkulima/data/room/converters/GAPConverters.kt @@ -0,0 +1,21 @@ +package com.steve_md.smartmkulima.data.room.converters + +import androidx.room.TypeConverter +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken +import com.steve_md.smartmkulima.model.Cycle +import com.steve_md.smartmkulima.model.GAPtask +import com.steve_md.smartmkulima.model.Tasks + +class Converters { + @TypeConverter + fun fromTasksList(tasks: List?): String? { + return Gson().toJson(tasks) + } + + @TypeConverter + fun toTasksList(tasksString: String?): List? { + val listType = object : TypeToken>() {}.type + return Gson().fromJson(tasksString, listType) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/steve_md/smartmkulima/data/room/converters/LocalFarmCycleConverter.kt b/app/src/main/java/com/steve_md/smartmkulima/data/room/converters/LocalFarmCycleConverter.kt new file mode 100644 index 00000000..4af8c67d --- /dev/null +++ b/app/src/main/java/com/steve_md/smartmkulima/data/room/converters/LocalFarmCycleConverter.kt @@ -0,0 +1,2 @@ +package com.steve_md.smartmkulima.data.room.converters + diff --git a/app/src/main/java/com/steve_md/smartmkulima/di/DatabaseModule.kt b/app/src/main/java/com/steve_md/smartmkulima/di/DatabaseModule.kt index 27c21fee..a3366ab2 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/di/DatabaseModule.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/di/DatabaseModule.kt @@ -4,6 +4,7 @@ import android.app.Application import androidx.room.Room import com.steve_md.smartmkulima.data.room.AppDatabase import com.steve_md.smartmkulima.data.room.FarmProduceDao +import com.steve_md.smartmkulima.data.room.GAPDao import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -30,4 +31,10 @@ object DatabaseModule { fun providesFarmProduceDao(appDatabase: AppDatabase): FarmProduceDao { return appDatabase.farmProduceDao() } + + @Provides + @Singleton + fun providesCycleDao(appDatabase: AppDatabase): GAPDao { + return appDatabase.gapDao() + } } \ No newline at end of file diff --git a/app/src/main/java/com/steve_md/smartmkulima/di/RepositoryModule.kt b/app/src/main/java/com/steve_md/smartmkulima/di/RepositoryModule.kt index b4b2f9bb..7dcf4b04 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/di/RepositoryModule.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/di/RepositoryModule.kt @@ -2,6 +2,7 @@ package com.steve_md.smartmkulima.di import com.steve_md.smartmkulima.data.remote.FarmProduceApiService import com.steve_md.smartmkulima.data.repositories.AuthRepository +import com.steve_md.smartmkulima.data.repositories.FarmCycleRepository import com.steve_md.smartmkulima.data.repositories.FarmProduceRepository import com.steve_md.smartmkulima.data.repositories.impl.AuthRepositoryImpl import com.steve_md.smartmkulima.data.room.AppDatabase @@ -27,6 +28,14 @@ object RepositoryModule { return FarmProduceRepository(farmProduceApiService, appDatabase) } + @Singleton + @Provides + fun providesFarmCycleRepo( + database: AppDatabase + ): FarmCycleRepository { + return FarmCycleRepository(database) + } + @Singleton @Provides fun providesDispatcher() = Dispatchers.Main as CoroutineDispatcher diff --git a/app/src/main/java/com/steve_md/smartmkulima/model/Cycle.kt b/app/src/main/java/com/steve_md/smartmkulima/model/Cycle.kt index cc5febcb..b1ad4b27 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/model/Cycle.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/model/Cycle.kt @@ -1,15 +1,18 @@ package com.steve_md.smartmkulima.model import android.os.Parcelable +import androidx.room.Entity +import androidx.room.PrimaryKey import kotlinx.parcelize.Parcelize /** * This data model class accommodates both crop cycle and service cycle */ +@Entity(tableName = "cycle") @Parcelize data class Cycle( - val farmId: String, + @PrimaryKey val farmId: String, val cropName: String, val startDate: String, val type: String, // "crop cycle" or "service cycle/livestock" @@ -17,9 +20,10 @@ data class Cycle( ) : Parcelable +@Entity(tableName = "cycle_tasks") @Parcelize data class Tasks ( - val taskName: String, + @PrimaryKey val taskName: String, val startDate: String, val endDate: String ) : Parcelable diff --git a/app/src/main/java/com/steve_md/smartmkulima/model/GAP.kt b/app/src/main/java/com/steve_md/smartmkulima/model/GAP.kt index cd1800d7..ed60ec1f 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/model/GAP.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/model/GAP.kt @@ -1,11 +1,17 @@ package com.steve_md.smartmkulima.model import android.os.Parcelable +import androidx.room.Entity +import androidx.room.PrimaryKey import kotlinx.parcelize.Parcelize +/** + * Illustrate how the GAP will look like + */ + @Parcelize data class GAP( - val nameGAP: String, + @PrimaryKey val nameGAP: String, val imageGAP: String, val gap: List ): Parcelable { @@ -39,9 +45,10 @@ data class GAP( * } el */ + @Parcelize data class GAPtask ( - val taskName: String, + @PrimaryKey val taskName: String, val startDate: String, val endDate: String ) : Parcelable diff --git a/app/src/main/java/com/steve_md/smartmkulima/model/LocalFarmCycle.kt b/app/src/main/java/com/steve_md/smartmkulima/model/LocalFarmCycle.kt new file mode 100644 index 00000000..006b68bb --- /dev/null +++ b/app/src/main/java/com/steve_md/smartmkulima/model/LocalFarmCycle.kt @@ -0,0 +1,2 @@ +package com.steve_md.smartmkulima.model + diff --git a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/main/HomeDashboardFragment.kt b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/main/HomeDashboardFragment.kt index 03556ea6..92689038 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/main/HomeDashboardFragment.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/main/HomeDashboardFragment.kt @@ -196,10 +196,13 @@ class HomeDashboardFragment : Fragment() { findNavController().navigate(R.id.action_homeDashboardFragment2_to_didYouKnow) } cardView9.setOnClickListener { - // TODO() - } + } textViewLastLoggedInTimeDate.text = "Last login: " +getLastLoginDayAndDate() + + tvViewAllGAPs.setOnClickListener { + findNavController().navigate(R.id.viewAllGAPsragment) + } } } } \ No newline at end of file diff --git a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/main/MonitorFarmConditionFragment.kt b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/main/MonitorFarmConditionFragment.kt index 6c1cc6e1..7b8b808d 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/main/MonitorFarmConditionFragment.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/main/MonitorFarmConditionFragment.kt @@ -69,6 +69,7 @@ class MonitorFarmConditionFragment : Fragment(),OnMapReadyCallback { } } + // Mock farm conditions with Fake DATA private fun monitorFarmConditions(latitude: Double, longitude: Double) { val mockFarmConditions = FarmConditions( temperature = 22.0, @@ -80,8 +81,6 @@ class MonitorFarmConditionFragment : Fragment(),OnMapReadyCallback { } private fun displayFarmConditions(mockFarmConditions: FarmConditions) { - // Update Farmers UI - // Calling all Views val temp = view?.findViewById(R.id.textViewTemperature) val humidity = view?.findViewById(R.id.textViewHumidity) val soilMoisture = view?.findViewById(R.id.textViewSoilMoisture) @@ -102,7 +101,6 @@ class MonitorFarmConditionFragment : Fragment(),OnMapReadyCallback { ) { googleMap.isMyLocationEnabled = true } else { - // Request location permission requestLocationPermission() } val location = LatLng(0.5699258, 34.5566803) diff --git a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/AutoCreateCropCycleFragment.kt b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/AutoCreateCropCycleFragment.kt index 3432c7ad..e7263a71 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/AutoCreateCropCycleFragment.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/AutoCreateCropCycleFragment.kt @@ -22,12 +22,18 @@ import androidx.appcompat.app.AppCompatActivity import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import com.google.firebase.firestore.FirebaseFirestore import com.steve_md.smartmkulima.R import com.steve_md.smartmkulima.databinding.FragmentAutoCreateCropCycleBinding import com.steve_md.smartmkulima.model.Cycle +import com.steve_md.smartmkulima.model.Tasks import com.steve_md.smartmkulima.utils.displaySnackBar +import com.steve_md.smartmkulima.viewmodel.MainViewModel +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch import timber.log.Timber import java.text.SimpleDateFormat import java.util.Calendar @@ -42,12 +48,12 @@ import java.util.Random * * Notify on upcoming tasks of different farm cycles */ + class AutoCreateCropCycleFragment : Fragment() { private lateinit var binding: FragmentAutoCreateCropCycleBinding private var cropCycleStartDay: Calendar? = null - private val cycleTypes by lazy { resources.getStringArray(R.array.cycle_types) } override fun onCreateView( @@ -93,8 +99,11 @@ class AutoCreateCropCycleFragment : Fragment() { val intentId = Intent(requireActivity(),AutoCreateCropCycleFragment::class.java) val pendingIntent = PendingIntent.getActivity( - requireActivity(),notificationId,intentId, - PendingIntent.FLAG_IMMUTABLE) + requireActivity(), + notificationId, + intentId, + PendingIntent.FLAG_IMMUTABLE + ) val builder = NotificationCompat.Builder(requireContext(), "notification_id") .setSmallIcon(R.drawable.ic_notification) @@ -201,6 +210,8 @@ class AutoCreateCropCycleFragment : Fragment() { if (selectedCropCycle == "Crop Cycle") { generateCropCycle() + + } else { //displayServiceCycleTasks() @@ -242,6 +253,8 @@ class AutoCreateCropCycleFragment : Fragment() { data class Step(val name: String, val startDay: Int, val endDay: Int) + + private fun generateCropCycle() { val selectedCycleType = binding.spinnerCycleType.selectedItem.toString() val startDayForCropCycle = binding.cropCycleStartDay.text.toString() @@ -270,6 +283,9 @@ class AutoCreateCropCycleFragment : Fragment() { ) + + + binding.stepLinearLayout.removeAllViews() for (stage in stages) { diff --git a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/CropCycleTasksListFragment.kt b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/CropCycleTasksListFragment.kt index 6117cc00..0fb087a9 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/CropCycleTasksListFragment.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/CropCycleTasksListFragment.kt @@ -9,7 +9,9 @@ import android.view.View import android.view.ViewGroup import android.view.inputmethod.EditorInfo import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.isVisible import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager import com.google.firebase.auth.FirebaseAuth @@ -26,12 +28,15 @@ import com.steve_md.smartmkulima.ui.fragments.main.HomeDashboardFragmentDirectio import com.steve_md.smartmkulima.utils.displaySnackBar import com.steve_md.smartmkulima.utils.hideKeyboard import com.steve_md.smartmkulima.utils.toast +import com.steve_md.smartmkulima.viewmodel.MainViewModel +import dagger.hilt.android.AndroidEntryPoint import retrofit2.Call import retrofit2.Response import timber.log.Timber import java.net.HttpURLConnection import java.util.logging.Handler +@AndroidEntryPoint class CropCycleTasksListFragment : Fragment() { private lateinit var binding: FragmentCropCycleListBinding private lateinit var cycleListAdapter: CropCycleTaskListAdapter @@ -130,8 +135,12 @@ class CropCycleTasksListFragment : Fragment() { } - // Fetch from remote API (web-service) + private fun getAllAvailableCropCycle() { + + + + // fetch from api(remote web service) CyclesApiClient.api.getAllFarmCycles() .enqueue(object : retrofit2.Callback> { @SuppressLint("NotifyDataSetChanged", "ResourceAsColor") diff --git a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/gap/ViewAllGAPsragment.kt b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/gap/ViewAllGAPsragment.kt new file mode 100644 index 00000000..b5ca73c6 --- /dev/null +++ b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/gap/ViewAllGAPsragment.kt @@ -0,0 +1,106 @@ +package com.steve_md.smartmkulima.ui.fragments.others.gap + +import android.annotation.SuppressLint +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import androidx.navigation.fragment.findNavController +import androidx.recyclerview.widget.LinearLayoutManager +import com.google.android.gms.maps.model.Gap +import com.steve_md.smartmkulima.R +import com.steve_md.smartmkulima.adapter.CropCycleTaskListAdapter +import com.steve_md.smartmkulima.adapter.GapAdapter +import com.steve_md.smartmkulima.data.remote.GapApiClient +import com.steve_md.smartmkulima.databinding.FragmentViewAllGAPsragmentBinding +import com.steve_md.smartmkulima.model.Cycle +import com.steve_md.smartmkulima.model.GAP +import com.steve_md.smartmkulima.ui.fragments.others.crop_cycle.CropCycleTasksListFragmentDirections +import dagger.hilt.android.AndroidEntryPoint +import retrofit2.Call +import retrofit2.Response +import timber.log.Timber + +/** + * This screen will list all Good Agricultural Practices(GAPs) + * nameGAP, startDate, endDate and the task list -> taskName + */ +@AndroidEntryPoint +class ViewAllGAPsragment : Fragment() { + + private lateinit var binding: FragmentViewAllGAPsragmentBinding + private lateinit var cycleListAdapter: GapAdapter + private var gapList = ArrayList() + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + // Inflate the layout for this fragment + binding = FragmentViewAllGAPsragmentBinding.inflate( + inflater, container, false + ) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + (activity as AppCompatActivity).supportActionBar?.hide() + setUpBinding() + setUpRecyclerView() + getGoodAgriculturalPractices() + } + private fun setUpRecyclerView() { + // Set the layout manager + binding.allGAPRecViewAll.layoutManager = LinearLayoutManager(requireContext()) + + // Initialize the adapter + cycleListAdapter = GapAdapter(GapAdapter.OnClickListener { gap -> + Timber.i("=====Checking=======>: ${gap.nameGAP} cycle") + + val dir = ViewAllGAPsragmentDirections.actionViewAllGAPsragmentToViewDetailsGAPTasksFragment(gap) + findNavController().navigate(directions = dir) + + }) + + // Set the adapter to the RecyclerView + binding.allGAPRecViewAll.adapter = cycleListAdapter + } + + private fun setUpBinding() { + + } + + private fun getGoodAgriculturalPractices() { + GapApiClient.api.getAllGAPs() + .enqueue(object : retrofit2.Callback> { + @SuppressLint("NotifyDataSetChanged", "ResourceAsColor") + override fun onResponse( + call: Call>, + response: Response> + ) { + if (response.isSuccessful) { + + Timber.i("==== Viewing Good Agri. practices${response.body()}=====") + // displaySnackBar("Viewing Available cycles") + + val gaps = response.body() + + gaps?.let { + gapList.addAll(it) + cycleListAdapter.submitList(gapList) + } + cycleListAdapter.notifyDataSetChanged() + binding.allGAPRecViewAll.adapter = cycleListAdapter + binding.allGAPRecViewAll.visibility = View.VISIBLE + } + } + override fun onFailure(call: Call>, t: Throwable) { + Timber.e("nothing here.${t.localizedMessage}") + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/gap/ViewDetailsGAPTasksFragment.kt b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/gap/ViewDetailsGAPTasksFragment.kt new file mode 100644 index 00000000..1e6fb35b --- /dev/null +++ b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/gap/ViewDetailsGAPTasksFragment.kt @@ -0,0 +1,65 @@ +package com.steve_md.smartmkulima.ui.fragments.others.gap + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import androidx.navigation.fragment.navArgs +import androidx.recyclerview.widget.LinearLayoutManager +import com.steve_md.smartmkulima.R +import com.steve_md.smartmkulima.adapter.DetailGapAdapter +import com.steve_md.smartmkulima.adapter.DetailTaskAdapter +import com.steve_md.smartmkulima.databinding.FragmentViewDetailsGAPTasksBinding +import com.steve_md.smartmkulima.ui.fragments.main.DetailedGAPArgs +import com.steve_md.smartmkulima.ui.fragments.others.crop_cycle.DetailedFarmCycleFragmentArgs +import com.steve_md.smartmkulima.utils.displaySnackBar +import timber.log.Timber + + +class ViewDetailsGAPTasksFragment : Fragment() { + + private lateinit var binding: FragmentViewDetailsGAPTasksBinding + private val detailedGapAdapter by lazy { DetailGapAdapter() } + + // Navigation Args + private val args: ViewDetailsGAPTasksFragmentArgs by navArgs() + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + + binding = FragmentViewDetailsGAPTasksBinding.inflate( + inflater, container, false + ) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + (activity as AppCompatActivity).supportActionBar?.hide() + + + val gap = args.gap + binding.apply { + // Link data with respective views + + showFarmId.text = gap.nameGAP + ShowCropName.text = "Good Agricultural Practice" + ShowStartDate.visibility = View.GONE + textView78.visibility = View.INVISIBLE + spinnerStatusOfFarmCycle.visibility = View.GONE + + Timber.tag("Detailed===>GAP").i("Viewing ${gap.nameGAP} cycle") + displaySnackBar("Viewing ${gap.nameGAP} cycle") + + detailedGapAdapter.submitList(gap.gap) + recyclerView.apply { + layoutManager = LinearLayoutManager(requireContext()) + adapter = detailedGapAdapter + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/steve_md/smartmkulima/utils/ExtensionFunctions.kt b/app/src/main/java/com/steve_md/smartmkulima/utils/ExtensionFunctions.kt index 57154eee..8598918b 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/utils/ExtensionFunctions.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/utils/ExtensionFunctions.kt @@ -12,6 +12,12 @@ import androidx.appcompat.app.AppCompatActivity import androidx.core.view.updateMargins import androidx.fragment.app.Fragment import com.google.android.material.snackbar.Snackbar +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import okhttp3.ResponseBody +import org.json.JSONException +import org.json.JSONObject +import retrofit2.HttpException fun Fragment.toast(text:String) { @@ -49,6 +55,64 @@ inline fun safeCall(action: () -> Resource): Resource { } } +sealed class ResourceNetwork { + data class Success( + val value: T + ) : ResourceNetwork() + data class Failure( + val isNetworkError: Boolean, + val errorCode: Int?, + val errorBody: ResponseBody?, + val errorString: String? + ) : ResourceNetwork() + + object Loading : ResourceNetwork() +} + +suspend fun apiRequestByResource(api: suspend () -> T): ResourceNetwork { + return withContext(Dispatchers.IO) { + try { + ResourceNetwork.Success(api.invoke()) + + } catch (throwable: Throwable) { + //Timber.e("HttpException throwable.message() ${throwable.message}") + if (throwable is HttpException) { +// Timber.e( +// "HttpException throwable.response() ${ +// throwable.response() +// }" + + + + // --------------------------------------------------------------------- + + val error = throwable.response()?.errorBody()!!.string() + val message = StringBuilder() + + error.let { + try { + message.append(JSONObject(it).getString("error_description")) + } catch (_: JSONException) { + } + message.append("\n") + } + + // Timber.e("BASE REPOSITORY----->>>>>>>>>>>>>>>>>> $message") + // --------------------------------------------------------------------- + ResourceNetwork.Failure( + false, + throwable.code(), + throwable.response()?.errorBody(), + error + ) + } else { + ResourceNetwork.Failure(true, null, null, "NO NETWORK FOUND") + } + } + } +} + + fun Fragment.makeStatusBarTransparent() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { requireActivity().window.apply { diff --git a/app/src/main/java/com/steve_md/smartmkulima/viewmodel/MainViewModel.kt b/app/src/main/java/com/steve_md/smartmkulima/viewmodel/MainViewModel.kt index c316c7aa..70396221 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/viewmodel/MainViewModel.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/viewmodel/MainViewModel.kt @@ -1,23 +1,40 @@ package com.steve_md.smartmkulima.viewmodel +import androidx.lifecycle.LiveData import androidx.lifecycle.ViewModel +import androidx.lifecycle.asLiveData import androidx.lifecycle.viewModelScope +import com.steve_md.smartmkulima.data.repositories.FarmCycleRepository import com.steve_md.smartmkulima.data.repositories.FarmProduceRepository +import com.steve_md.smartmkulima.model.Cycle import com.steve_md.smartmkulima.model.FarmProduce import com.steve_md.smartmkulima.utils.ApiStates import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import timber.log.Timber import javax.inject.Inject @HiltViewModel class MainViewModel @Inject constructor( - private val farmProduceRepository: FarmProduceRepository + private val farmProduceRepository: FarmProduceRepository, + private val repository: FarmCycleRepository ) : ViewModel() { + + val allCycles: LiveData> = repository.allCycles.asLiveData() + + fun addCropCycle(cycle: Cycle) = viewModelScope.launch { + withContext(Dispatchers.IO) { + repository.insertCycle(cycle) + } + } + + init { getAllFarmProduce() } diff --git a/app/src/main/res/layout/fragment_crop_cycle_list.xml b/app/src/main/res/layout/fragment_crop_cycle_list.xml index 182f8db6..7b8f332a 100644 --- a/app/src/main/res/layout/fragment_crop_cycle_list.xml +++ b/app/src/main/res/layout/fragment_crop_cycle_list.xml @@ -72,8 +72,9 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home_dashboard.xml b/app/src/main/res/layout/fragment_home_dashboard.xml index ccc37322..bce7b1ce 100644 --- a/app/src/main/res/layout/fragment_home_dashboard.xml +++ b/app/src/main/res/layout/fragment_home_dashboard.xml @@ -7,6 +7,7 @@ android:layout_height="match_parent" android:background="@color/bg_gray" android:fillViewport="true" + android:scrollbars="none" android:fitsSystemWindows="true" tools:context=".ui.fragments.main.HomeDashboardFragment"> @@ -317,12 +318,22 @@ android:id="@+id/home_gap_recyclerView" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="16dp" + android:layout_marginTop="48dp" app:spanCount="2" app:layoutManager="androidx.recyclerview.widget.GridLayoutManager" tools:listitem="@layout/home_gap_row" app:layout_constraintTop_toBottomOf="@+id/TopicsChipGroup" /> + + diff --git a/app/src/main/res/layout/fragment_view_all_g_a_psragment.xml b/app/src/main/res/layout/fragment_view_all_g_a_psragment.xml new file mode 100644 index 00000000..3b71917c --- /dev/null +++ b/app/src/main/res/layout/fragment_view_all_g_a_psragment.xml @@ -0,0 +1,35 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_view_details_g_a_p_tasks.xml b/app/src/main/res/layout/fragment_view_details_g_a_p_tasks.xml new file mode 100644 index 00000000..ef0a3031 --- /dev/null +++ b/app/src/main/res/layout/fragment_view_details_g_a_p_tasks.xml @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/navigation_graph.xml b/app/src/main/res/navigation/navigation_graph.xml index 20e09fe3..50f234e0 100644 --- a/app/src/main/res/navigation/navigation_graph.xml +++ b/app/src/main/res/navigation/navigation_graph.xml @@ -238,6 +238,9 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 11eafada..6eea26f6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -27,6 +27,7 @@ Block A TextView Last login: Apr 10, 2024 + View All GAPs Crop Cycle From 30d5961f1583bcb63cc1b203f2030913f3164e7c Mon Sep 17 00:00:00 2001 From: "muindi.stephen" Date: Sat, 20 Jul 2024 20:08:41 +0300 Subject: [PATCH 2/6] Added some recycler view adapter --- .../smartmkulima/adapter/GapAdapter.kt | 2 +- .../adapter/others/LocalFarmCycleAdapter.kt | 58 ++++++ .../others/LocalFarmCycleTasksAdapter.kt | 47 +++++ .../data/repositories/FarmCycleRepository.kt | 13 +- .../smartmkulima/data/room/AppDatabase.kt | 12 +- .../data/room/LocalFarmCycleDao.kt | 21 +++ .../converters/LocalFarmCycleConverter.kt | 20 ++ .../com/steve_md/smartmkulima/model/Cycle.kt | 1 + .../smartmkulima/model/LocalFarmCycle.kt | 22 +++ .../ui/fragments/main/PaymentFragment.kt | 4 +- .../crop_cycle/AutoCreateCropCycleFragment.kt | 173 +++++++++++++++++- .../CropCycleCreationAndScheduleFragment.kt | 2 + .../smartmkulima/viewmodel/MainViewModel.kt | 5 +- .../fragment_auto_create_crop_cycle.xml | 19 +- app/src/main/res/values/strings.xml | 12 +- 15 files changed, 391 insertions(+), 20 deletions(-) create mode 100644 app/src/main/java/com/steve_md/smartmkulima/adapter/others/LocalFarmCycleAdapter.kt create mode 100644 app/src/main/java/com/steve_md/smartmkulima/adapter/others/LocalFarmCycleTasksAdapter.kt diff --git a/app/src/main/java/com/steve_md/smartmkulima/adapter/GapAdapter.kt b/app/src/main/java/com/steve_md/smartmkulima/adapter/GapAdapter.kt index a0c5b1b6..baa13b4c 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/adapter/GapAdapter.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/adapter/GapAdapter.kt @@ -11,7 +11,7 @@ import com.steve_md.smartmkulima.databinding.HomeGapRowBinding import com.steve_md.smartmkulima.model.GAP /** - * Bind fetched GAPS to the Ui (Recycler View) + * - Bind fetched GAPS to the Ui (Recycler View) * - In order to display a list of available GAPs to the RecyclerView Ui */ class GapAdapter(private val onClickListener: OnClickListener) : diff --git a/app/src/main/java/com/steve_md/smartmkulima/adapter/others/LocalFarmCycleAdapter.kt b/app/src/main/java/com/steve_md/smartmkulima/adapter/others/LocalFarmCycleAdapter.kt new file mode 100644 index 00000000..549404a2 --- /dev/null +++ b/app/src/main/java/com/steve_md/smartmkulima/adapter/others/LocalFarmCycleAdapter.kt @@ -0,0 +1,58 @@ +package com.steve_md.smartmkulima.adapter.others + +import android.annotation.SuppressLint +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import com.steve_md.smartmkulima.databinding.CropCycleTaskRowBinding +import com.steve_md.smartmkulima.model.LocalFarmCycle + +/** + * Attach data to locally created Farm cycles to Room DB + */ +class LocalFarmCycleAdapter(private val onClickListener: OnClickListener) : + ListAdapter(TaskDiffUtil) { + + object TaskDiffUtil : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: LocalFarmCycle, newItem: LocalFarmCycle): Boolean { + return oldItem == newItem + } + + override fun areContentsTheSame(oldItem: LocalFarmCycle, newItem: LocalFarmCycle): Boolean { + return oldItem.cropName == newItem.cropName + } + } + + inner class MyViewHolder(private var binding: CropCycleTaskRowBinding) : + RecyclerView.ViewHolder(binding.root) { + + @SuppressLint("SetTextI18n") + fun bind(cycle: LocalFarmCycle?) { + binding.farmID.text = cycle?.farmName + binding.cycleData.text = cycle?.cropName + binding.dateForCycle.text = cycle?.startDate + binding.textView85.text = "Crop cycle" + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { + return MyViewHolder( + CropCycleTaskRowBinding.inflate(LayoutInflater.from(parent.context), parent, false) + ) + } + + override fun onBindViewHolder(holder: MyViewHolder, position: Int) { + val cycle = getItem(position) + holder.bind(cycle) + + holder.itemView.setOnClickListener { + onClickListener.onClick(cycle = cycle) + } + } + + class OnClickListener(val clickListener: (cycle: LocalFarmCycle) -> Unit) { + fun onClick(cycle: LocalFarmCycle) = clickListener(cycle) + } +} diff --git a/app/src/main/java/com/steve_md/smartmkulima/adapter/others/LocalFarmCycleTasksAdapter.kt b/app/src/main/java/com/steve_md/smartmkulima/adapter/others/LocalFarmCycleTasksAdapter.kt new file mode 100644 index 00000000..cae285e3 --- /dev/null +++ b/app/src/main/java/com/steve_md/smartmkulima/adapter/others/LocalFarmCycleTasksAdapter.kt @@ -0,0 +1,47 @@ +package com.steve_md.smartmkulima.adapter.others + +import android.annotation.SuppressLint +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.steve_md.smartmkulima.databinding.DetailCycleRowBinding +import com.steve_md.smartmkulima.model.LocalTasks + +/** + * Able to view actual tasks for cycle - respective tasks + */ +class LocalFarmCycleTasksAdapter : RecyclerView.Adapter() { + + private var tasks: List = ArrayList() + + inner class TaskViewHolder(private val binding: DetailCycleRowBinding) : + RecyclerView.ViewHolder(binding.root) { + + fun bind(task: LocalTasks) { + binding.textView75.text = task.taskName + binding.textView76.text = task.startDate + binding.textView77.text = task.endDate + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TaskViewHolder { + val binding = + DetailCycleRowBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return TaskViewHolder(binding) + } + + override fun onBindViewHolder(holder: TaskViewHolder, position: Int) { + val task = tasks[position] + holder.bind(task) + } + + override fun getItemCount(): Int { + return tasks.size + } + + @SuppressLint("NotifyDataSetChanged") + fun submitList(taskList: List) { + tasks = taskList + notifyDataSetChanged() + } +} diff --git a/app/src/main/java/com/steve_md/smartmkulima/data/repositories/FarmCycleRepository.kt b/app/src/main/java/com/steve_md/smartmkulima/data/repositories/FarmCycleRepository.kt index 89ea55c8..f19664e7 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/data/repositories/FarmCycleRepository.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/data/repositories/FarmCycleRepository.kt @@ -2,11 +2,14 @@ package com.steve_md.smartmkulima.data.repositories import com.steve_md.smartmkulima.data.room.AppDatabase import com.steve_md.smartmkulima.data.room.GAPDao +import com.steve_md.smartmkulima.data.room.LocalFarmCycleDao import com.steve_md.smartmkulima.model.Cycle import com.steve_md.smartmkulima.model.GAP +import com.steve_md.smartmkulima.model.LocalFarmCycle import com.steve_md.smartmkulima.utils.apiRequestByResource import com.steve_md.smartmkulima.utils.safeCall import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow import javax.inject.Inject /** @@ -18,10 +21,16 @@ class FarmCycleRepository @Inject constructor( ) { private val gapDao: GAPDao = database.gapDao() - suspend fun insertCycle(cycle: Cycle) = apiRequestByResource { - gapDao.insertGAP(cycle) + private val localCycleDao: LocalFarmCycleDao = database.localFarmCycleDao() + + suspend fun insertCycle(cycle: LocalFarmCycle) = apiRequestByResource { + localCycleDao.insertLocalFarmCycle(cycle) } val allCycles : Flow> = gapDao.getAllCycle() + val allLocalFarmCyle: Flow> = flow { + localCycleDao.getAllFarmCycle() + } + } \ No newline at end of file diff --git a/app/src/main/java/com/steve_md/smartmkulima/data/room/AppDatabase.kt b/app/src/main/java/com/steve_md/smartmkulima/data/room/AppDatabase.kt index b0c1ac85..c854ce58 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/data/room/AppDatabase.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/data/room/AppDatabase.kt @@ -4,17 +4,17 @@ import androidx.room.Database import androidx.room.RoomDatabase import androidx.room.TypeConverters import com.steve_md.smartmkulima.data.room.converters.Converters +import com.steve_md.smartmkulima.data.room.converters.LocalFarmCycleConverter import com.steve_md.smartmkulima.model.Cycle import com.steve_md.smartmkulima.model.FarmProduce -import com.steve_md.smartmkulima.model.GAP -import com.steve_md.smartmkulima.model.GAPtask -import com.steve_md.smartmkulima.model.Task +import com.steve_md.smartmkulima.model.LocalFarmCycle import com.steve_md.smartmkulima.model.Tasks import com.steve_md.smartmkulima.model.Transaction -@TypeConverters(Converters::class) -@Database(entities = [Transaction::class,FarmProduce::class, Cycle::class, Tasks::class], version = 3, exportSchema = false) +@TypeConverters(Converters::class,LocalFarmCycleConverter::class) +@Database(entities = [Transaction::class, FarmProduce::class, Cycle::class, + Tasks::class, LocalFarmCycle::class], version = 4, exportSchema = false) abstract class AppDatabase : RoomDatabase() { abstract fun transactionDao(): TransactionDao @@ -22,6 +22,8 @@ abstract class AppDatabase : RoomDatabase() { abstract fun gapDao(): GAPDao + abstract fun localFarmCycleDao(): LocalFarmCycleDao + /** * Implement singleton pattern in room to prevent * multiple instances of room database opening at the sametime diff --git a/app/src/main/java/com/steve_md/smartmkulima/data/room/LocalFarmCycleDao.kt b/app/src/main/java/com/steve_md/smartmkulima/data/room/LocalFarmCycleDao.kt index ce7cc046..cb4f04f7 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/data/room/LocalFarmCycleDao.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/data/room/LocalFarmCycleDao.kt @@ -1,4 +1,25 @@ package com.steve_md.smartmkulima.data.room +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Update +import com.steve_md.smartmkulima.model.LocalFarmCycle +import kotlinx.coroutines.flow.Flow + + +@Dao interface LocalFarmCycleDao { + + @Insert + suspend fun insertLocalFarmCycle(localFarmCycle: LocalFarmCycle) + + @Update + suspend fun updateLocalFarmCycle(localFarmCycle: LocalFarmCycle) + + @Query("SELECT * FROM localcycle WHERE cropName = :cropName") + suspend fun getFarmCycleBYName(cropName: String): LocalFarmCycle? + + @Query("SELECT * FROM localcycle") + fun getAllFarmCycle(): Flow> } \ No newline at end of file diff --git a/app/src/main/java/com/steve_md/smartmkulima/data/room/converters/LocalFarmCycleConverter.kt b/app/src/main/java/com/steve_md/smartmkulima/data/room/converters/LocalFarmCycleConverter.kt index 4af8c67d..72ea4d24 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/data/room/converters/LocalFarmCycleConverter.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/data/room/converters/LocalFarmCycleConverter.kt @@ -1,2 +1,22 @@ package com.steve_md.smartmkulima.data.room.converters +import androidx.room.TypeConverter +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken +import com.steve_md.smartmkulima.model.LocalTasks + +class LocalFarmCycleConverter { + @TypeConverter + fun fromLocalTasksList(value: List?): String { + val gson = Gson() + val type = object : TypeToken>() {}.type + return gson.toJson(value, type) + } + + @TypeConverter + fun toLocalTasksList(value: String): List? { + val gson = Gson() + val type = object : TypeToken>() {}.type + return gson.fromJson(value, type) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/steve_md/smartmkulima/model/Cycle.kt b/app/src/main/java/com/steve_md/smartmkulima/model/Cycle.kt index b1ad4b27..1499b020 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/model/Cycle.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/model/Cycle.kt @@ -27,3 +27,4 @@ data class Tasks ( val startDate: String, val endDate: String ) : Parcelable + diff --git a/app/src/main/java/com/steve_md/smartmkulima/model/LocalFarmCycle.kt b/app/src/main/java/com/steve_md/smartmkulima/model/LocalFarmCycle.kt index 006b68bb..bc1e1975 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/model/LocalFarmCycle.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/model/LocalFarmCycle.kt @@ -1,2 +1,24 @@ package com.steve_md.smartmkulima.model +import android.os.Parcelable +import androidx.room.Entity +import androidx.room.PrimaryKey +import kotlinx.parcelize.Parcelize + +@Entity(tableName = "localcycle") +@Parcelize +data class LocalFarmCycle( + val farmName: String, + @PrimaryKey val cropName: String, + val startDate: String, + val tasks: List +) : Parcelable + + +@Entity(tableName = "cycle_tasks") +@Parcelize +data class LocalTasks ( + @PrimaryKey val taskName: String, + val startDate: String, + val endDate: String +) : Parcelable diff --git a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/main/PaymentFragment.kt b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/main/PaymentFragment.kt index bdbe57fb..9e865edd 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/main/PaymentFragment.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/main/PaymentFragment.kt @@ -41,7 +41,9 @@ import java.text.SimpleDateFormat import java.util.* /** - * Initiates Mpesa STK push for payment based on inputs @phone @amount + * Initiates Mpesa STK push for payment based on inputs + * @param phone + * @param amount */ @AndroidEntryPoint class PaymentFragment : Fragment(), View.OnClickListener { diff --git a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/AutoCreateCropCycleFragment.kt b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/AutoCreateCropCycleFragment.kt index e7263a71..5ec53deb 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/AutoCreateCropCycleFragment.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/AutoCreateCropCycleFragment.kt @@ -1,7 +1,6 @@ package com.steve_md.smartmkulima.ui.fragments.others.crop_cycle import android.annotation.SuppressLint -import android.app.AlertDialog import android.app.DatePickerDialog import android.app.NotificationChannel import android.app.NotificationManager @@ -25,17 +24,22 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController -import com.google.firebase.firestore.FirebaseFirestore import com.steve_md.smartmkulima.R +import com.steve_md.smartmkulima.data.remote.GapApiClient import com.steve_md.smartmkulima.databinding.FragmentAutoCreateCropCycleBinding -import com.steve_md.smartmkulima.model.Cycle -import com.steve_md.smartmkulima.model.Tasks +import com.steve_md.smartmkulima.model.GAP +import com.steve_md.smartmkulima.model.GAPtask +import com.steve_md.smartmkulima.model.LocalFarmCycle +import com.steve_md.smartmkulima.model.LocalTasks import com.steve_md.smartmkulima.utils.displaySnackBar import com.steve_md.smartmkulima.viewmodel.MainViewModel import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch +import retrofit2.Call +import retrofit2.Response import timber.log.Timber import java.text.SimpleDateFormat +import java.util.ArrayList import java.util.Calendar import java.util.Locale import java.util.Random @@ -49,13 +53,17 @@ import java.util.Random * Notify on upcoming tasks of different farm cycles */ +@AndroidEntryPoint class AutoCreateCropCycleFragment : Fragment() { private lateinit var binding: FragmentAutoCreateCropCycleBinding private var cropCycleStartDay: Calendar? = null + private var selectedCrop: String = "" private val cycleTypes by lazy { resources.getStringArray(R.array.cycle_types) } + private val farmCycleViewModel: MainViewModel by viewModels() + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? @@ -72,12 +80,167 @@ class AutoCreateCropCycleFragment : Fragment() { super.onViewCreated(view, savedInstanceState) (activity as AppCompatActivity).supportActionBar?.hide() + + binding.imageViewBackFromAutoCreateCropCycle.setOnClickListener { + findNavController().navigateUp() + } + + cropCycleStartDay = Calendar.getInstance() - setUpBinding() + // setUpBinding() scheduleNotification(2) + + + val cropList = resources.getStringArray(R.array.crop_list) + val cropAdapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, cropList) + cropAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + binding.spinnerCrops.adapter = cropAdapter + + binding.spinnerCrops.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>, view: View?, position: Int, id: Long) { + selectedCrop = parent.getItemAtPosition(position).toString() + Timber.i("Selected Crop: $selectedCrop") + displaySnackBar(selectedCrop) + } + + override fun onNothingSelected(parent: AdapterView<*>) { + displaySnackBar("Nothing selected") + } + } + + // Fetch first GAPs which are linked to Creation of crop cycles with exact date and time + binding.buttonGeneratorCropCycle.setOnClickListener { +// val selectedCrop = binding.spinnerCrops.selectedItem.toString() + getGoodAgriculturalPractices(selectedCrop) + } + + configureUi() + } + + private fun configureUi() { + binding.cropCycleStartDay.setOnFocusChangeListener { _, hasFocus -> + if (hasFocus) { + showDatePickerDialog() + } + } + } + + + private fun getGoodAgriculturalPractices(selectedCrop: String) { + GapApiClient.api.getAllGAPs() + .enqueue(object : retrofit2.Callback> { + @SuppressLint("NotifyDataSetChanged", "ResourceAsColor") + override fun onResponse( + call: Call>, + response: Response> + ) { + if (response.isSuccessful) { + + val gapList = response.body() + if (gapList != null) { + // Filter GAPs based on the selected crop + val gapForSelectedCrop = + gapList.find { it.nameGAP.equals(selectedCrop, ignoreCase = true) } + if (gapForSelectedCrop != null) { + createCropCycle( + selectedCrop, + binding.enterFarmBlockID.text.toString(), + cropCycleStartDay, + gapForSelectedCrop.gap + ) + } + } + +// val ga +// var gapFound = false +// +// Timber.i("==== Viewing Good Agri. practices${response.body()}=====") +// // displaySnackBar("Viewing Available cycles") +// +// response.body()?.forEach { gapResponse -> +// if (gapResponse.nameGAP.equals(selectedCrop, ignoreCase = true)) { +// createCropCycle( +// selectedCrop, +// binding.enterFarmBlockID.text.toString(), +// cropCycleStartDay, +// gapResponse.gap +// ) +// } +// } + +// if (!gapFound) { +// Timber.w("No GAP found for the selected crop: $selectedCrop") +// requireActivity().runOnUiThread { +// displaySnackBar("No GAP found for the selected crop: $selectedCrop") +// } +// } + + } else { + Timber.e("Response was not successful: ${response.message()}") + Timber.w("No GAP found for the selected crop: $selectedCrop") + requireActivity().runOnUiThread { + displaySnackBar("No GAP found for the selected crop: $selectedCrop") + } + } + } + override fun onFailure(call: Call>, t: Throwable) { + Timber.e("nothing here.${t.localizedMessage}") + } + }) } + private fun createCropCycle( + selectedCrop: String, + farmName: String, + startDate: Calendar?, + gap: List + ) { + + + val dateFormat = SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()) + val calendar = startDate ?: Calendar.getInstance() + + val localTasksList = mutableListOf() + + gap.forEach { gapTask -> + val taskStartDate = calendar.clone() as Calendar + val taskEndDate = calendar.clone() as Calendar + taskEndDate.add(Calendar.DATE, gapTask.endDate.toInt()) + + val task = LocalTasks( + taskName = gapTask.taskName, + startDate = dateFormat.format(taskStartDate.time), + endDate = dateFormat.format(taskEndDate.time) + ) + localTasksList.add(task) + calendar.add(Calendar.DATE, gapTask.endDate.toInt()) + } + + val localFarmCycle = LocalFarmCycle( + farmName = farmName, + cropName = selectedCrop, + startDate = dateFormat.format(startDate?.time ?: Calendar.getInstance().time), + tasks = localTasksList + ) + + lifecycleScope.launch { + farmCycleViewModel.addCropCycle(localFarmCycle).runCatching { + displaySnackBar("") + } + + runCatching { + + } + Log.e("AutoCreateCropCycleFragment","$localFarmCycle") + + requireActivity().runOnUiThread { + displaySnackBar("Crop cycle for $selectedCrop created successfully!") + } + } + } + + @SuppressLint("SetTextI18n") private fun scheduleNotification(daysLater: Int) { val notificationManager = diff --git a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/CropCycleCreationAndScheduleFragment.kt b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/CropCycleCreationAndScheduleFragment.kt index f11dfa0c..8ceb08d5 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/CropCycleCreationAndScheduleFragment.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/CropCycleCreationAndScheduleFragment.kt @@ -57,6 +57,8 @@ class CropCycleCreationAndScheduleFragment : Fragment() { initBinding() initScheduleCropCycleTask() + + } private fun initScheduleCropCycleTask() { binding.buttonGenerateSchedule.setOnClickListener { generateSchedule() } diff --git a/app/src/main/java/com/steve_md/smartmkulima/viewmodel/MainViewModel.kt b/app/src/main/java/com/steve_md/smartmkulima/viewmodel/MainViewModel.kt index 70396221..531a48e8 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/viewmodel/MainViewModel.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/viewmodel/MainViewModel.kt @@ -8,6 +8,7 @@ import com.steve_md.smartmkulima.data.repositories.FarmCycleRepository import com.steve_md.smartmkulima.data.repositories.FarmProduceRepository import com.steve_md.smartmkulima.model.Cycle import com.steve_md.smartmkulima.model.FarmProduce +import com.steve_md.smartmkulima.model.LocalFarmCycle import com.steve_md.smartmkulima.utils.ApiStates import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers @@ -26,9 +27,9 @@ class MainViewModel @Inject constructor( ) : ViewModel() { - val allCycles: LiveData> = repository.allCycles.asLiveData() + val allCycles: LiveData> = repository.allLocalFarmCyle.asLiveData() - fun addCropCycle(cycle: Cycle) = viewModelScope.launch { + fun addCropCycle(cycle: LocalFarmCycle) = viewModelScope.launch { withContext(Dispatchers.IO) { repository.insertCycle(cycle) } diff --git a/app/src/main/res/layout/fragment_auto_create_crop_cycle.xml b/app/src/main/res/layout/fragment_auto_create_crop_cycle.xml index dd453f78..9412e377 100644 --- a/app/src/main/res/layout/fragment_auto_create_crop_cycle.xml +++ b/app/src/main/res/layout/fragment_auto_create_crop_cycle.xml @@ -64,6 +64,21 @@ android:paddingHorizontal="12dp" android:paddingVertical="8dp" android:spinnerMode="dropdown" + android:visibility="invisible" + android:background="@drawable/rounded_corner" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + @@ -78,8 +93,8 @@ android:fontFamily="@font/montserrat_medium" android:textColor="@color/textColor" android:hint="Enter Start Day?" - app:layout_constraintStart_toStartOf="@id/spinnerCycleType" - app:layout_constraintTop_toBottomOf="@+id/spinnerCycleType" + app:layout_constraintStart_toStartOf="@id/spinnerCrops" + app:layout_constraintTop_toBottomOf="@+id/spinnerCrops" android:inputType="date" /> - Coriander Capsicum Geva - Cucumber Mydas Tomatoes Anna + Coriander + Cucumber Mydas Cucumber English Cucumber Bologna Capsicum Spinach + Tomatoes Anna F1 + Backup-Tomatoes Anna F1 + Cucumber Carmen + Tomatoes Gold Sun + Tomatoes Golden Sun + Capsicum + Tomatoes Big Rock F1 + Lettuce Bullet Chillies From f6665af46e03e3d4a1b924430a325c0327e7f761 Mon Sep 17 00:00:00 2001 From: "muindi.stephen" Date: Sun, 21 Jul 2024 01:32:01 +0300 Subject: [PATCH 3/6] Attach data, and fix some bugs --- .../crop_cycle/AutoCreateCropCycleFragment.kt | 10 +- .../crop_cycle/CropCycleTasksListFragment.kt | 102 ++++++++++-------- .../crop_cycle/DetailedFarmCycleFragment.kt | 7 +- .../res/layout/fragment_crop_cycle_list.xml | 28 ----- .../main/res/navigation/navigation_graph.xml | 2 +- 5 files changed, 69 insertions(+), 80 deletions(-) diff --git a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/AutoCreateCropCycleFragment.kt b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/AutoCreateCropCycleFragment.kt index 5ec53deb..d41468e2 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/AutoCreateCropCycleFragment.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/AutoCreateCropCycleFragment.kt @@ -85,6 +85,9 @@ class AutoCreateCropCycleFragment : Fragment() { findNavController().navigateUp() } + binding.viewAllCycleTypes.setOnClickListener { + goToCropCycle() + } cropCycleStartDay = Calendar.getInstance() // setUpBinding() @@ -225,13 +228,8 @@ class AutoCreateCropCycleFragment : Fragment() { ) lifecycleScope.launch { - farmCycleViewModel.addCropCycle(localFarmCycle).runCatching { - displaySnackBar("") - } - - runCatching { + farmCycleViewModel.addCropCycle(localFarmCycle) - } Log.e("AutoCreateCropCycleFragment","$localFarmCycle") requireActivity().runOnUiThread { diff --git a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/CropCycleTasksListFragment.kt b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/CropCycleTasksListFragment.kt index 0fb087a9..79f96425 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/CropCycleTasksListFragment.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/CropCycleTasksListFragment.kt @@ -1,30 +1,23 @@ package com.steve_md.smartmkulima.ui.fragments.others.crop_cycle import android.annotation.SuppressLint -import android.content.res.ColorStateList -import android.graphics.Color import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.view.inputmethod.EditorInfo import androidx.appcompat.app.AppCompatActivity -import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager -import com.google.firebase.auth.FirebaseAuth -import com.google.firebase.firestore.FirebaseFirestore -import com.steve_md.smartmkulima.R import com.steve_md.smartmkulima.adapter.CropCycleTaskListAdapter +import com.steve_md.smartmkulima.adapter.others.LocalFarmCycleAdapter import com.steve_md.smartmkulima.data.remote.CyclesApiClient -import com.steve_md.smartmkulima.data.remote.FarmEquipmentsApiClient import com.steve_md.smartmkulima.databinding.FragmentCropCycleListBinding -import com.steve_md.smartmkulima.model.CropCycleTask import com.steve_md.smartmkulima.model.Cycle -import com.steve_md.smartmkulima.model.FarmEquipment -import com.steve_md.smartmkulima.ui.fragments.main.HomeDashboardFragmentDirections +import com.steve_md.smartmkulima.model.LocalFarmCycle import com.steve_md.smartmkulima.utils.displaySnackBar import com.steve_md.smartmkulima.utils.hideKeyboard import com.steve_md.smartmkulima.utils.toast @@ -33,14 +26,18 @@ import dagger.hilt.android.AndroidEntryPoint import retrofit2.Call import retrofit2.Response import timber.log.Timber -import java.net.HttpURLConnection -import java.util.logging.Handler @AndroidEntryPoint class CropCycleTasksListFragment : Fragment() { private lateinit var binding: FragmentCropCycleListBinding - private lateinit var cycleListAdapter: CropCycleTaskListAdapter - private var cycleList = ArrayList() + //private lateinit var cycleListAdapter: CropCycleTaskListAdapter + private var cycleList = ArrayList() + + + + private lateinit var localFarmCycleAdapter: LocalFarmCycleAdapter + + private val viewModel: MainViewModel by viewModels() override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -59,7 +56,32 @@ class CropCycleTasksListFragment : Fragment() { setUpBinding() setUpRecyclerView() - getAllAvailableCropCycle() + // getAllAvailableCropCycle() + + + getAllCreatedCycles() + } + + @SuppressLint("NotifyDataSetChanged") + private fun getAllCreatedCycles() { + viewModel.allCycles.observe(viewLifecycleOwner){ it -> + when(it.isEmpty()) { + true -> { + displaySnackBar("No created farm cycles available") + } + false -> { + it?.let { + cycleList.addAll(it) + localFarmCycleAdapter.submitList(cycleList) + } + localFarmCycleAdapter.notifyDataSetChanged() + binding.cropCycleRecyclerView.adapter = localFarmCycleAdapter + binding.cropCycleRecyclerView.visibility = View.VISIBLE + + displaySnackBar("Alert! Created farm cycles") + } + } + } } private fun setUpRecyclerView() { @@ -67,18 +89,19 @@ class CropCycleTasksListFragment : Fragment() { binding.cropCycleRecyclerView.layoutManager = LinearLayoutManager(requireContext()) // Initialize the adapter - cycleListAdapter = CropCycleTaskListAdapter(CropCycleTaskListAdapter.OnClickListener { cycle -> + + localFarmCycleAdapter = LocalFarmCycleAdapter(LocalFarmCycleAdapter.OnClickListener{ cycle-> + Log.e("...CreatedFarmCycles....", cycle.toString()) + Timber.i("=====Checking=======>: ${cycle.cropName} cycle") - val directions = CropCycleTasksListFragmentDirections.actionCropCycleTasksListFragmentToDetailedFarmCycleFragment( - cycle - ) + val directions = CropCycleTasksListFragmentDirections + .actionCropCycleTasksListFragmentToDetailedFarmCycleFragment(cycle) findNavController().navigate(directions) - }) // Set the adapter to the RecyclerView - binding.cropCycleRecyclerView.adapter = cycleListAdapter + binding.cropCycleRecyclerView.adapter = localFarmCycleAdapter } @SuppressLint("ResourceAsColor") @@ -86,7 +109,7 @@ class CropCycleTasksListFragment : Fragment() { binding.imageViewBackFromCropCycleLists.setOnClickListener { findNavController().navigateUp() } binding.textView74.setOnClickListener { - // binding.cropCycleRecyclerView.removeAllViews() + // binding.cropCycleRecyclerView.removeAllViews() binding.progressBarCycles.visibility = View.VISIBLE android.os.Handler().postDelayed({ binding.progressBarCycles.visibility = View.GONE @@ -96,11 +119,11 @@ class CropCycleTasksListFragment : Fragment() { binding.textView83CropCycle.setOnClickListener { //binding.cropCycleRecyclerView.removeAllViews() - filterCycles("Crop cycle") + filterCycles("") } binding.textView84.setOnClickListener { - // binding.cropCycleRecyclerView.removeAllViews() - filterCycles("Livestock cycle") + // binding.cropCycleRecyclerView.removeAllViews() + filterCycles("") } binding.searchProduct.setOnEditorActionListener { _, actionId, _ -> @@ -130,16 +153,11 @@ class CropCycleTasksListFragment : Fragment() { } binding.searchView.editText?.setText("") - getAllAvailableCropCycle() + getAllCreatedCycles() } } - - private fun getAllAvailableCropCycle() { - - - // fetch from api(remote web service) CyclesApiClient.api.getAllFarmCycles() .enqueue(object : retrofit2.Callback> { @@ -155,13 +173,13 @@ class CropCycleTasksListFragment : Fragment() { val cycles = response.body() - cycles?.let { - cycleList.addAll(it) - cycleListAdapter.submitList(cycleList) - } - cycleListAdapter.notifyDataSetChanged() - binding.cropCycleRecyclerView.adapter = cycleListAdapter - binding.cropCycleRecyclerView.visibility = View.VISIBLE +// cycles?.let { +// cycleList.addAll(it) +// cycleListAdapter.submitList(cycleList) +// } +// cycleListAdapter.notifyDataSetChanged() +// binding.cropCycleRecyclerView.adapter = cycleListAdapter +// binding.cropCycleRecyclerView.visibility = View.VISIBLE } } override fun onFailure(call: Call>, t: Throwable) { @@ -173,11 +191,11 @@ class CropCycleTasksListFragment : Fragment() { } private fun searching(s: String) { - val filteredList = cycleList.filter { it.farmId.equals(s, ignoreCase = true) } - cycleListAdapter.submitList(filteredList.toMutableList()) + val filteredList = cycleList.filter { it.cropName.equals(s, ignoreCase = true) } + localFarmCycleAdapter.submitList(filteredList.toMutableList()) } private fun filterCycles(s: String) { - val filteredList = cycleList.filter { it.type.equals(s, ignoreCase = true) } - cycleListAdapter.submitList(filteredList.toMutableList()) + val filteredList = cycleList.filter { it.farmName.equals(s, ignoreCase = true) } + localFarmCycleAdapter.submitList(filteredList.toMutableList()) } } diff --git a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/DetailedFarmCycleFragment.kt b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/DetailedFarmCycleFragment.kt index 40ae6a75..dcf41fa0 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/DetailedFarmCycleFragment.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/DetailedFarmCycleFragment.kt @@ -10,13 +10,14 @@ import androidx.fragment.app.Fragment import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.LinearLayoutManager import com.steve_md.smartmkulima.adapter.DetailTaskAdapter +import com.steve_md.smartmkulima.adapter.others.LocalFarmCycleTasksAdapter import com.steve_md.smartmkulima.databinding.FragmentDetailedFarmCycleBinding import com.steve_md.smartmkulima.utils.displaySnackBar import timber.log.Timber class DetailedFarmCycleFragment : Fragment() { private lateinit var binding: FragmentDetailedFarmCycleBinding - private val tasksAdapter by lazy { DetailTaskAdapter() } + private val tasksAdapter by lazy { LocalFarmCycleTasksAdapter() } // Navigation Args private val args: DetailedFarmCycleFragmentArgs by navArgs() @@ -41,10 +42,10 @@ class DetailedFarmCycleFragment : Fragment() { binding.apply { // Link data with respective views - showFarmId.text = cycle.farmId + showFarmId.text = "" ShowCropName.text = cycle.cropName ShowStartDate.text = cycle.startDate - textView78.text = cycle.type + textView78.text = "Crop cycle" Timber.tag(this@DetailedFarmCycleFragment.toString()).i("Viewing ${cycle.cropName} cycle") displaySnackBar("Viewing ${cycle.cropName} cycle") diff --git a/app/src/main/res/layout/fragment_crop_cycle_list.xml b/app/src/main/res/layout/fragment_crop_cycle_list.xml index 7b8f332a..d9be525e 100644 --- a/app/src/main/res/layout/fragment_crop_cycle_list.xml +++ b/app/src/main/res/layout/fragment_crop_cycle_list.xml @@ -67,14 +67,11 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/navigation/navigation_graph.xml b/app/src/main/res/navigation/navigation_graph.xml index 50f234e0..edd1e036 100644 --- a/app/src/main/res/navigation/navigation_graph.xml +++ b/app/src/main/res/navigation/navigation_graph.xml @@ -445,7 +445,7 @@ tools:layout="@layout/fragment_detailed_farm_cycle" > + app:argType="com.steve_md.smartmkulima.model.LocalFarmCycle" /> Date: Sun, 21 Jul 2024 15:50:38 +0300 Subject: [PATCH 4/6] Some fixes --- .../data/repositories/FarmCycleRepository.kt | 8 +++- .../data/room/LocalFarmCycleDao.kt | 3 +- .../com/steve_md/smartmkulima/model/GAP.kt | 2 +- .../crop_cycle/AutoCreateCropCycleFragment.kt | 48 +++++++++++-------- .../crop_cycle/CropCycleTasksListFragment.kt | 28 ++++++++--- .../crop_cycle/DetailedFarmCycleFragment.kt | 2 + .../steve_md/smartmkulima/utils/DateFormat.kt | 7 +++ .../smartmkulima/viewmodel/MainViewModel.kt | 8 ++-- 8 files changed, 72 insertions(+), 34 deletions(-) diff --git a/app/src/main/java/com/steve_md/smartmkulima/data/repositories/FarmCycleRepository.kt b/app/src/main/java/com/steve_md/smartmkulima/data/repositories/FarmCycleRepository.kt index f19664e7..ee2db076 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/data/repositories/FarmCycleRepository.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/data/repositories/FarmCycleRepository.kt @@ -1,5 +1,6 @@ package com.steve_md.smartmkulima.data.repositories +import androidx.lifecycle.LiveData import com.steve_md.smartmkulima.data.room.AppDatabase import com.steve_md.smartmkulima.data.room.GAPDao import com.steve_md.smartmkulima.data.room.LocalFarmCycleDao @@ -29,8 +30,11 @@ class FarmCycleRepository @Inject constructor( val allCycles : Flow> = gapDao.getAllCycle() - val allLocalFarmCyle: Flow> = flow { - localCycleDao.getAllFarmCycle() + + + + fun getAllCycles(): LiveData> { + return localCycleDao.getAllFarmCycle() } } \ No newline at end of file diff --git a/app/src/main/java/com/steve_md/smartmkulima/data/room/LocalFarmCycleDao.kt b/app/src/main/java/com/steve_md/smartmkulima/data/room/LocalFarmCycleDao.kt index cb4f04f7..ba68cfcd 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/data/room/LocalFarmCycleDao.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/data/room/LocalFarmCycleDao.kt @@ -1,5 +1,6 @@ package com.steve_md.smartmkulima.data.room +import androidx.lifecycle.LiveData import androidx.room.Dao import androidx.room.Insert import androidx.room.Query @@ -21,5 +22,5 @@ interface LocalFarmCycleDao { suspend fun getFarmCycleBYName(cropName: String): LocalFarmCycle? @Query("SELECT * FROM localcycle") - fun getAllFarmCycle(): Flow> + fun getAllFarmCycle(): LiveData> } \ No newline at end of file diff --git a/app/src/main/java/com/steve_md/smartmkulima/model/GAP.kt b/app/src/main/java/com/steve_md/smartmkulima/model/GAP.kt index ed60ec1f..f0345aff 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/model/GAP.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/model/GAP.kt @@ -13,7 +13,7 @@ import kotlinx.parcelize.Parcelize data class GAP( @PrimaryKey val nameGAP: String, val imageGAP: String, - val gap: List + var gap: List ): Parcelable { override fun equals(other: Any?): Boolean { if (this === other) return true diff --git a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/AutoCreateCropCycleFragment.kt b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/AutoCreateCropCycleFragment.kt index d41468e2..b6709daa 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/AutoCreateCropCycleFragment.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/AutoCreateCropCycleFragment.kt @@ -31,6 +31,8 @@ import com.steve_md.smartmkulima.model.GAP import com.steve_md.smartmkulima.model.GAPtask import com.steve_md.smartmkulima.model.LocalFarmCycle import com.steve_md.smartmkulima.model.LocalTasks +import com.steve_md.smartmkulima.utils.DateFormat.formatDate +import com.steve_md.smartmkulima.utils.DateFormat.getWhenStarts import com.steve_md.smartmkulima.utils.displaySnackBar import com.steve_md.smartmkulima.viewmodel.MainViewModel import dagger.hilt.android.AndroidEntryPoint @@ -64,6 +66,7 @@ class AutoCreateCropCycleFragment : Fragment() { private val farmCycleViewModel: MainViewModel by viewModels() + var task : LocalTasks? = LocalTasks("","","") override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? @@ -80,7 +83,6 @@ class AutoCreateCropCycleFragment : Fragment() { super.onViewCreated(view, savedInstanceState) (activity as AppCompatActivity).supportActionBar?.hide() - binding.imageViewBackFromAutoCreateCropCycle.setOnClickListener { findNavController().navigateUp() } @@ -145,7 +147,12 @@ class AutoCreateCropCycleFragment : Fragment() { // Filter GAPs based on the selected crop val gapForSelectedCrop = gapList.find { it.nameGAP.equals(selectedCrop, ignoreCase = true) } + if (gapForSelectedCrop != null) { + + gapList.map { + gapForSelectedCrop.gap = it.gap + } createCropCycle( selectedCrop, binding.enterFarmBlockID.text.toString(), @@ -199,8 +206,6 @@ class AutoCreateCropCycleFragment : Fragment() { startDate: Calendar?, gap: List ) { - - val dateFormat = SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()) val calendar = startDate ?: Calendar.getInstance() @@ -211,29 +216,37 @@ class AutoCreateCropCycleFragment : Fragment() { val taskEndDate = calendar.clone() as Calendar taskEndDate.add(Calendar.DATE, gapTask.endDate.toInt()) - val task = LocalTasks( + task = LocalTasks( taskName = gapTask.taskName, startDate = dateFormat.format(taskStartDate.time), endDate = dateFormat.format(taskEndDate.time) ) - localTasksList.add(task) + localTasksList.add(task!!) calendar.add(Calendar.DATE, gapTask.endDate.toInt()) } + val dateFormat1 = SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()) + val calendar1 = startDate ?: Calendar.getInstance() + + val testStartDate = calendar1.clone() as Calendar + val localFarmCycle = LocalFarmCycle( farmName = farmName, cropName = selectedCrop, - startDate = dateFormat.format(startDate?.time ?: Calendar.getInstance().time), + startDate = getWhenStarts()!!, tasks = localTasksList ) lifecycleScope.launch { - farmCycleViewModel.addCropCycle(localFarmCycle) - - Log.e("AutoCreateCropCycleFragment","$localFarmCycle") - - requireActivity().runOnUiThread { - displaySnackBar("Crop cycle for $selectedCrop created successfully!") + try { + farmCycleViewModel.addCropCycle(localFarmCycle) + Log.d("AutoCreateCropCycleFragment","Added crop cycle: $localFarmCycle") + requireActivity().runOnUiThread { + displaySnackBar("Crop cycle for $selectedCrop created successfully!") + } + } catch (e: Exception) { + Log.e("AutoCreateCropCycleFragment", "Error adding crop cycle: ${e.message}") + displaySnackBar("Failed to create Farm Cycle: ${e.message}") } } } @@ -371,15 +384,7 @@ class AutoCreateCropCycleFragment : Fragment() { if (selectedCropCycle == "Crop Cycle") { generateCropCycle() - - } else { - //displayServiceCycleTasks() - -// val stepTextView = TextView(requireContext()) -// stepTextView.text = "SERVNext Heat -> Drying -> Steaming -> Calving" -// binding.stepLinearLayout.addView(stepTextView) - displayPredefinedServiceCycle() } } @@ -490,7 +495,7 @@ class AutoCreateCropCycleFragment : Fragment() { { _, selectedYear, selectedMonth, selectedDay -> // Update the selected date in the UI cropCycleStartDay?.set(selectedYear, selectedMonth, selectedDay) - val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) + val dateFormat = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()) binding.cropCycleStartDay.setText(dateFormat.format(cropCycleStartDay!!.time)) }, year, @@ -500,6 +505,7 @@ class AutoCreateCropCycleFragment : Fragment() { datePickerDialog.show() } + private fun getStageDescription(stageName: String): String { return when (stageName) { "Seedling Acquisition" -> "Start Day: ${cropCycleStartDay!!.time} - End Day: 2024-03-10" diff --git a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/CropCycleTasksListFragment.kt b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/CropCycleTasksListFragment.kt index 79f96425..17456c1d 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/CropCycleTasksListFragment.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/CropCycleTasksListFragment.kt @@ -8,6 +8,7 @@ import android.view.View import android.view.ViewGroup import android.view.inputmethod.EditorInfo import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController @@ -31,9 +32,7 @@ import timber.log.Timber class CropCycleTasksListFragment : Fragment() { private lateinit var binding: FragmentCropCycleListBinding //private lateinit var cycleListAdapter: CropCycleTaskListAdapter - private var cycleList = ArrayList() - - + private var cycleList = mutableListOf() private lateinit var localFarmCycleAdapter: LocalFarmCycleAdapter @@ -54,17 +53,20 @@ class CropCycleTasksListFragment : Fragment() { (activity as AppCompatActivity).supportActionBar?.hide() - setUpBinding() + binding.imageViewBackFromCropCycleLists.setOnClickListener { + findNavController().navigateUp() + } + + //setUpBinding() setUpRecyclerView() // getAllAvailableCropCycle() - getAllCreatedCycles() } @SuppressLint("NotifyDataSetChanged") private fun getAllCreatedCycles() { - viewModel.allCycles.observe(viewLifecycleOwner){ it -> + /**viewModel.allCycles.observe(viewLifecycleOwner){ it -> when(it.isEmpty()) { true -> { displaySnackBar("No created farm cycles available") @@ -82,6 +84,17 @@ class CropCycleTasksListFragment : Fragment() { } } } + */ + + viewModel.allCycles.observe(viewLifecycleOwner) { cycles -> + if (cycles.isNullOrEmpty()) { + displaySnackBar("No created farm cycles available") + } else { + cycleList.clear() + cycleList.addAll(cycles) + localFarmCycleAdapter.submitList(cycleList.toList()) + } + } } private fun setUpRecyclerView() { @@ -117,10 +130,13 @@ class CropCycleTasksListFragment : Fragment() { }, 1000) } + binding.textView83CropCycle.isVisible = false binding.textView83CropCycle.setOnClickListener { //binding.cropCycleRecyclerView.removeAllViews() filterCycles("") } + + binding.textView84.isVisible = false binding.textView84.setOnClickListener { // binding.cropCycleRecyclerView.removeAllViews() filterCycles("") diff --git a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/DetailedFarmCycleFragment.kt b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/DetailedFarmCycleFragment.kt index dcf41fa0..d709be61 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/DetailedFarmCycleFragment.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/DetailedFarmCycleFragment.kt @@ -13,8 +13,10 @@ import com.steve_md.smartmkulima.adapter.DetailTaskAdapter import com.steve_md.smartmkulima.adapter.others.LocalFarmCycleTasksAdapter import com.steve_md.smartmkulima.databinding.FragmentDetailedFarmCycleBinding import com.steve_md.smartmkulima.utils.displaySnackBar +import dagger.hilt.android.AndroidEntryPoint import timber.log.Timber +@AndroidEntryPoint class DetailedFarmCycleFragment : Fragment() { private lateinit var binding: FragmentDetailedFarmCycleBinding private val tasksAdapter by lazy { LocalFarmCycleTasksAdapter() } diff --git a/app/src/main/java/com/steve_md/smartmkulima/utils/DateFormat.kt b/app/src/main/java/com/steve_md/smartmkulima/utils/DateFormat.kt index 479aa2f3..f5cde94f 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/utils/DateFormat.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/utils/DateFormat.kt @@ -26,4 +26,11 @@ object DateFormat { return sdf.format(cal.time) } + @SuppressLint("SimpleDateFormat") + fun getWhenStarts(): String? { + val cal = Calendar.getInstance() + val sdf = SimpleDateFormat("d-MM-yyyy") + return sdf.format(cal.time) + } + } \ No newline at end of file diff --git a/app/src/main/java/com/steve_md/smartmkulima/viewmodel/MainViewModel.kt b/app/src/main/java/com/steve_md/smartmkulima/viewmodel/MainViewModel.kt index 531a48e8..8723a717 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/viewmodel/MainViewModel.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/viewmodel/MainViewModel.kt @@ -26,8 +26,11 @@ class MainViewModel @Inject constructor( private val repository: FarmCycleRepository ) : ViewModel() { + private val _produce = MutableSharedFlow() + val produce: SharedFlow = _produce + - val allCycles: LiveData> = repository.allLocalFarmCyle.asLiveData() + val allCycles: LiveData> = repository.getAllCycles() fun addCropCycle(cycle: LocalFarmCycle) = viewModelScope.launch { withContext(Dispatchers.IO) { @@ -40,8 +43,7 @@ class MainViewModel @Inject constructor( getAllFarmProduce() } - private val _produce = MutableSharedFlow() - val produce: SharedFlow = _produce + private fun getAllFarmProduce() { From b9ae5ce6545a99bf3285f8f3981ab4edaca7fb1b Mon Sep 17 00:00:00 2001 From: "muindi.stephen" Date: Sun, 21 Jul 2024 16:02:52 +0300 Subject: [PATCH 5/6] Filtering locally saved crop cycles working! --- .../others/crop_cycle/CropCycleTasksListFragment.kt | 5 +++-- app/src/main/res/layout/fragment_crop_cycle_list.xml | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/CropCycleTasksListFragment.kt b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/CropCycleTasksListFragment.kt index 17456c1d..e70af2c0 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/CropCycleTasksListFragment.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/CropCycleTasksListFragment.kt @@ -57,7 +57,7 @@ class CropCycleTasksListFragment : Fragment() { findNavController().navigateUp() } - //setUpBinding() + setUpBinding() setUpRecyclerView() // getAllAvailableCropCycle() @@ -119,8 +119,9 @@ class CropCycleTasksListFragment : Fragment() { @SuppressLint("ResourceAsColor") private fun setUpBinding() { - binding.imageViewBackFromCropCycleLists.setOnClickListener { findNavController().navigateUp() } + // binding.imageViewBackFromCropCycleLists.setOnClickListener { findNavController().navigateUp() } + binding.textView84.isVisible = false binding.textView74.setOnClickListener { // binding.cropCycleRecyclerView.removeAllViews() binding.progressBarCycles.visibility = View.VISIBLE diff --git a/app/src/main/res/layout/fragment_crop_cycle_list.xml b/app/src/main/res/layout/fragment_crop_cycle_list.xml index d9be525e..d17846dc 100644 --- a/app/src/main/res/layout/fragment_crop_cycle_list.xml +++ b/app/src/main/res/layout/fragment_crop_cycle_list.xml @@ -112,6 +112,7 @@ android:layout_marginEnd="140dp" android:fontFamily="@font/montserrat_semibold" android:text="Filter by:" + android:visibility="invisible" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="1.0" app:layout_constraintStart_toEndOf="@+id/textView74" From 7e3ca3282819398f1553a84aabd20b5ac033f5b0 Mon Sep 17 00:00:00 2001 From: "muindi.stephen" Date: Sun, 21 Jul 2024 17:04:42 +0300 Subject: [PATCH 6/6] Debugging done, another release and update --- .../data/repositories/FarmCycleRepository.kt | 4 ++ .../smartmkulima/data/room/AppDatabase.kt | 2 +- .../data/room/LocalFarmCycleDao.kt | 3 ++ .../smartmkulima/di/DatabaseModule.kt | 8 ++++ .../smartmkulima/model/LocalFarmCycle.kt | 3 +- .../crop_cycle/CropCycleTasksListFragment.kt | 15 +++++++ .../crop_cycle/DetailedFarmCycleFragment.kt | 41 +++++++++++++++++++ .../smartmkulima/viewmodel/MainViewModel.kt | 3 ++ .../layout/fragment_detailed_farm_cycle.xml | 11 ++++- 9 files changed, 87 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/steve_md/smartmkulima/data/repositories/FarmCycleRepository.kt b/app/src/main/java/com/steve_md/smartmkulima/data/repositories/FarmCycleRepository.kt index ee2db076..efdaddb3 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/data/repositories/FarmCycleRepository.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/data/repositories/FarmCycleRepository.kt @@ -37,4 +37,8 @@ class FarmCycleRepository @Inject constructor( return localCycleDao.getAllFarmCycle() } + suspend fun updateTaskStatus(status: String) { + localCycleDao.updateTaskStatus(status) + } + } \ No newline at end of file diff --git a/app/src/main/java/com/steve_md/smartmkulima/data/room/AppDatabase.kt b/app/src/main/java/com/steve_md/smartmkulima/data/room/AppDatabase.kt index c854ce58..ea472824 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/data/room/AppDatabase.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/data/room/AppDatabase.kt @@ -14,7 +14,7 @@ import com.steve_md.smartmkulima.model.Transaction @TypeConverters(Converters::class,LocalFarmCycleConverter::class) @Database(entities = [Transaction::class, FarmProduce::class, Cycle::class, - Tasks::class, LocalFarmCycle::class], version = 4, exportSchema = false) + Tasks::class, LocalFarmCycle::class], version = 5, exportSchema = false) abstract class AppDatabase : RoomDatabase() { abstract fun transactionDao(): TransactionDao diff --git a/app/src/main/java/com/steve_md/smartmkulima/data/room/LocalFarmCycleDao.kt b/app/src/main/java/com/steve_md/smartmkulima/data/room/LocalFarmCycleDao.kt index ba68cfcd..fc4919e9 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/data/room/LocalFarmCycleDao.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/data/room/LocalFarmCycleDao.kt @@ -23,4 +23,7 @@ interface LocalFarmCycleDao { @Query("SELECT * FROM localcycle") fun getAllFarmCycle(): LiveData> + + @Query("UPDATE localcycle SET status = :status") + suspend fun updateTaskStatus(status: String) } \ No newline at end of file diff --git a/app/src/main/java/com/steve_md/smartmkulima/di/DatabaseModule.kt b/app/src/main/java/com/steve_md/smartmkulima/di/DatabaseModule.kt index a3366ab2..dca803af 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/di/DatabaseModule.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/di/DatabaseModule.kt @@ -2,6 +2,8 @@ package com.steve_md.smartmkulima.di import android.app.Application import androidx.room.Room +import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase import com.steve_md.smartmkulima.data.room.AppDatabase import com.steve_md.smartmkulima.data.room.FarmProduceDao import com.steve_md.smartmkulima.data.room.GAPDao @@ -26,6 +28,12 @@ object DatabaseModule { .build() } + + private val MIGRATION_1_2 = object : Migration(1, 2) { + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("ALTER TABLE localcycle ADD COLUMN status TEXT NOT NULL DEFAULT 'Upcoming'") + } + } @Provides @Singleton fun providesFarmProduceDao(appDatabase: AppDatabase): FarmProduceDao { diff --git a/app/src/main/java/com/steve_md/smartmkulima/model/LocalFarmCycle.kt b/app/src/main/java/com/steve_md/smartmkulima/model/LocalFarmCycle.kt index bc1e1975..f841e16c 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/model/LocalFarmCycle.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/model/LocalFarmCycle.kt @@ -11,7 +11,8 @@ data class LocalFarmCycle( val farmName: String, @PrimaryKey val cropName: String, val startDate: String, - val tasks: List + val tasks: List, + val status: String = "Upcoming" ) : Parcelable diff --git a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/CropCycleTasksListFragment.kt b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/CropCycleTasksListFragment.kt index e70af2c0..b3eca692 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/CropCycleTasksListFragment.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/CropCycleTasksListFragment.kt @@ -28,6 +28,21 @@ import retrofit2.Call import retrofit2.Response import timber.log.Timber +/** + * + * Hey! + * This code looks Junk :( + * @author MuindiStephen - Github + * + * @year 2024 + * + * Was written in hurry to solve an issue + * & to implement a feature in urgency + * + * + * + * + */ @AndroidEntryPoint class CropCycleTasksListFragment : Fragment() { private lateinit var binding: FragmentCropCycleListBinding diff --git a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/DetailedFarmCycleFragment.kt b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/DetailedFarmCycleFragment.kt index d709be61..1b133932 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/DetailedFarmCycleFragment.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/ui/fragments/others/crop_cycle/DetailedFarmCycleFragment.kt @@ -1,18 +1,23 @@ package com.steve_md.smartmkulima.ui.fragments.others.crop_cycle import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.AdapterView +import android.widget.ArrayAdapter import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.LinearLayoutManager import com.steve_md.smartmkulima.adapter.DetailTaskAdapter import com.steve_md.smartmkulima.adapter.others.LocalFarmCycleTasksAdapter import com.steve_md.smartmkulima.databinding.FragmentDetailedFarmCycleBinding import com.steve_md.smartmkulima.utils.displaySnackBar +import com.steve_md.smartmkulima.viewmodel.MainViewModel import dagger.hilt.android.AndroidEntryPoint import timber.log.Timber @@ -24,6 +29,8 @@ class DetailedFarmCycleFragment : Fragment() { // Navigation Args private val args: DetailedFarmCycleFragmentArgs by navArgs() + private val viewModel: MainViewModel by viewModels() + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? @@ -40,10 +47,44 @@ class DetailedFarmCycleFragment : Fragment() { (activity as AppCompatActivity).supportActionBar?.hide() + val setStatus = binding.spinnerStatusOfFarmCycle.selectedItem.toString() + viewModel.updateTaskStatus(setStatus) + binding.textView86.text = setStatus + +// +// binding.spinnerStatusOfFarmCycle.setSelection( +// (binding.spinnerStatusOfFarmCycle.adapter as ArrayAdapter<*>).getPosition(setStatus as Nothing?) +// ) + + /* + binding.spinnerStatusOfFarmCycle.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected( + parent: AdapterView<*>?, + view: View?, + position: Int, + id: Long + ) { + viewModel.updateTaskStatus(setStatus) + binding.textView86.text = setStatus + displaySnackBar(setStatus) + } + + override fun onNothingSelected(parent: AdapterView<*>?) { + Log.e("STATUS","Nothing") + } + + } + + */ + + + + val cycle = args.cycle binding.apply { // Link data with respective views + showFarmId.text = "" ShowCropName.text = cycle.cropName ShowStartDate.text = cycle.startDate diff --git a/app/src/main/java/com/steve_md/smartmkulima/viewmodel/MainViewModel.kt b/app/src/main/java/com/steve_md/smartmkulima/viewmodel/MainViewModel.kt index 8723a717..355973dd 100644 --- a/app/src/main/java/com/steve_md/smartmkulima/viewmodel/MainViewModel.kt +++ b/app/src/main/java/com/steve_md/smartmkulima/viewmodel/MainViewModel.kt @@ -38,6 +38,9 @@ class MainViewModel @Inject constructor( } } + fun updateTaskStatus(status: String) = viewModelScope.launch { + repository.updateTaskStatus(status) + } init { getAllFarmProduce() diff --git a/app/src/main/res/layout/fragment_detailed_farm_cycle.xml b/app/src/main/res/layout/fragment_detailed_farm_cycle.xml index 356b1216..b7f2bdc6 100644 --- a/app/src/main/res/layout/fragment_detailed_farm_cycle.xml +++ b/app/src/main/res/layout/fragment_detailed_farm_cycle.xml @@ -148,6 +148,15 @@ android:spinnerMode="dropdown" app:layout_constraintBottom_toBottomOf="@+id/textView78" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toEndOf="@+id/textView78" app:layout_constraintTop_toTopOf="@+id/textView78" /> + + \ No newline at end of file