working on filter and add sites

This commit is contained in:
Aryankc2 2025-04-24 18:27:18 +05:30
parent 76eaed7ba2
commit 3ea869a22f
24 changed files with 710 additions and 106 deletions

View file

@ -59,6 +59,7 @@ dependencies {
implementation(libs.okhttp)
implementation(libs.logging.interceptor)
implementation(libs.androidx.swiperefreshlayout)
implementation(libs.glide)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)

View file

@ -4,7 +4,11 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<application
android:name=".AgentApplication"
android:allowBackup="true"
@ -20,6 +24,7 @@
android:name=".ui.SplashActivity"
android:exported="true"
android:theme="@style/Theme.FieldAgent"
android:screenOrientation="portrait"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -29,10 +34,24 @@
</activity>
<activity
android:name=".ui.login.LoginActivity"
android:exported="true"/>
android:exported="true"
android:screenOrientation="portrait"
/>
<activity
android:name=".ui.homescreen.HomeActivity"
android:exported="true" />
android:exported="true"
android:screenOrientation="portrait"
/>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
</manifest>

View file

@ -1,17 +1,11 @@
package com.example.fieldagent.data.apis
import com.example.fieldagent.data.models.responses.UserData
import com.example.fieldagent.data.network.responseUtil.ApiResponse
import retrofit2.http.FieldMap
import retrofit2.http.FormUrlEncoded
import retrofit2.http.POST
import com.example.fieldagent.data.models.responses.*
import com.example.fieldagent.data.network.responseUtil.ApiResponse
import okhttp3.RequestBody
import retrofit2.Call
import retrofit2.http.DELETE
import retrofit2.http.GET
import retrofit2.http.PUT
import retrofit2.http.Path
import retrofit2.http.QueryMap
import retrofit2.http.*
interface WebService {
companion object {
@ -125,15 +119,16 @@ interface WebService {
/*POST APIS*/
@FormUrlEncoded
@POST(LOGIN)
fun login(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<UserData>>
fun login(@FieldMap hashMap: HashMap<String, Any>): Call<UserData>
@GET(INSPECTIONS_LIST)
fun inspectionsList(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<UserData>>
fun inspectionsList(@QueryMap hashMap: Map<String, String>): Call<InspectionData>
@Multipart
@POST(CREATE_INSPECTION)
fun createInspections(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<UserData>>
fun createInspections(@PartMap map: HashMap<String, RequestBody>): Call<UserData>
@GET(DAMAGES)
@ -141,7 +136,7 @@ interface WebService {
@POST(DAMAGES)
fun createDamage(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<UserData>>
fun createDamage(@FieldMap hashMap: Map<String, String>): Call<ApiResponse<UserData>>
@DELETE("$DELETE_INSPECTIONS/{id}")

View file

@ -0,0 +1,43 @@
package com.example.fieldagent.data.models.responses
data class InspectionData (
val status: Long? = null,
val success: Boolean? = null,
val message: String? = null,
val data: ListData? = null
)
data class ListData (
val inspections: List<InspectionList>? = null,
val pagination: Pagination? = null
)
data class InspectionList (
val id: Long? = null,
val userID: Long? = null,
val name: String? = null,
val location: String? = null,
val supervisorName: String? = null,
val supervisorPhoneNumber: String? = null,
val siteCondition: String? = null,
val area: Long? = null,
val womenPrayerArea: Boolean? = null,
val totalCapacity: Long? = null,
val totalRestrooms: Long? = null,
val isCompleted: Boolean? = null,
val isDeleted: Boolean? = null,
val createdAt: String? = null,
val updatedAt: String? = null,
val damages: List<Any?>? = null
)
data class Pagination (
val total: Long? = null,
val page: Long? = null,
val limit: Long? = null,
val totalPages: Long? = null,
val hasNextPage: Boolean? = null,
val hasPrevPage: Boolean? = null
)

View file

@ -1,11 +1,13 @@
package com.example.fieldagent.data.models.responses
import java.io.Serializable
data class UserData (
val status: Long? = null,
val success: Boolean? = null,
val message: String? = null,
val data: Data? = null
)
):Serializable
data class Data (
val id: Long? = null,
@ -16,9 +18,9 @@ data class Data (
val createdAt: String? = null,
val updatedAt: String? = null,
val tokens: Tokens? = null
)
):Serializable
data class Tokens (
val accessToken: String? = null,
val refreshToken: String? = null
)
):Serializable

View file

@ -1,9 +1,11 @@
package com.example.fieldagent.di
import android.util.Log
import com.example.fieldagent.data.apis.WebService
import com.example.fieldagent.data.models.responses.UserData
import com.example.fieldagent.data.network.Config
import com.example.fieldagent.utils.PrefsManager
import com.example.fieldagent.utils.TOKEN
import com.example.fieldagent.utils.USER_DATA
import com.google.gson.Gson
import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory
@ -53,13 +55,18 @@ object NetworkModule {
.build()
}
private fun getNetworkInterceptor(prefsManager: PrefsManager): Interceptor {
return Interceptor { chain ->
var request = chain.request()
val requestBuilder = request.newBuilder()
requestBuilder.addHeader("Accept", "application/json")
.header("Connection", "close")
val accessToken = prefsManager.getObject(USER_DATA, UserData::class.java)?.data?.tokens?.accessToken
.addHeader("timezone", TimeZone.getDefault().id)
val accessToken = prefsManager.getString(TOKEN,"")
if (!accessToken.isNullOrEmpty())
requestBuilder.addHeader("authorization", "Bearer $accessToken")

View file

@ -1,25 +1,81 @@
package com.example.fieldagent.ui.addsite
import android.Manifest
import android.app.Dialog
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.util.Log
import android.util.Patterns
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.widget.ArrayAdapter
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.FileProvider
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import androidx.navigation.fragment.findNavController
import com.bumptech.glide.Glide
import com.consultantapp.data.network.responseUtil.Status
import com.example.fieldagent.R
import com.example.fieldagent.data.models.responses.UserData
import com.example.fieldagent.data.network.ApisRespHandler
import com.example.fieldagent.databinding.FragmentAddSiteBinding
import com.example.fieldagent.databinding.FragmentHomeBinding
import com.example.fieldagent.databinding.SelectPhotoBinding
import com.example.fieldagent.ui.homescreen.HomeViewModel
import com.example.fieldagent.ui.homescreen.adapter.HomeAdapter
import com.example.fieldagent.utils.PER_PAGE_LOAD
import com.example.fieldagent.utils.PrefsManager
import com.example.fieldagent.utils.dialogs.ProgressDialog
import com.example.fieldagent.utils.getRequestBody
import com.example.fieldagent.utils.gone
import com.example.fieldagent.utils.hideShowView
import com.example.fieldagent.utils.isConnectedToInternet
import com.example.fieldagent.utils.showSnackBar
import com.example.fieldagent.utils.visible
import dagger.hilt.android.AndroidEntryPoint
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.asRequestBody
import java.io.File
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import javax.inject.Inject
@AndroidEntryPoint
class AddSiteFragment : Fragment() {
private var _binding: FragmentAddSiteBinding? = null
private val binding get() = _binding!!
private val viewModel: AddSiteViewModel by viewModels()
@Inject
lateinit var prefsManager: PrefsManager
private lateinit var progressDialog: ProgressDialog
private var image:String="";
private var selectWomenPrayerArea:String=""
private var selectRestroom:String=""
private lateinit var cameraLauncher: ActivityResultLauncher<Uri>
private lateinit var galleryLauncher: ActivityResultLauncher<String>
private lateinit var permissionLauncher: ActivityResultLauncher<Array<String>>
private var imageUri: Uri? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
@ -32,7 +88,18 @@ class AddSiteFragment : Fragment() {
super.onViewCreated(view, savedInstanceState)
initialize()
listener()
bindObservers()
}
private fun initialize() {
selectWomenPrayerArea=getString(R.string.yes)
selectRestroom=getString(R.string.ok_condition)
val options = resources.getStringArray(R.array.availability).toList()
val adapter = ArrayAdapter(requireActivity(), R.layout.dropdown_item, options)
@ -43,6 +110,12 @@ class AddSiteFragment : Fragment() {
binding.autoCompleteBuilding.showDropDown()
}
binding.autoCompleteBuilding.setOnItemClickListener { parent, view, position, id ->
val selectedItem = parent.getItemAtPosition(position) as String
Log.d("SELECTED_ITEM", "User selected: $selectedItem")
selectWomenPrayerArea=selectedItem;
}
val options2 = resources.getStringArray(R.array.condition).toList()
val adapter2 = ArrayAdapter(requireActivity(), R.layout.dropdown_item, options2)
@ -54,18 +127,189 @@ class AddSiteFragment : Fragment() {
binding.autoCompleteTextView.showDropDown()
}
binding.autoCompleteBuilding.setOnItemClickListener { parent, view, position, id ->
val selectedItem = parent.getItemAtPosition(position) as String
Log.d("SELECTED_ITEM", "User selected: $selectedItem")
selectRestroom=selectedItem;
}
}
private fun listener(){
binding.ivLeft.setOnClickListener {
findNavController().popBackStack()
}
binding.btnAdd.setOnClickListener {
when{
binding.etName.text.toString().isEmpty() -> {
binding.etName.showSnackBar(getString(R.string.please_enter_your_name))
}
binding.etLocation.text.toString().isEmpty() -> {
binding.etLocation.showSnackBar(getString(R.string.please_enter_your_location))
}
binding.etSupervisorContact.text.toString().isEmpty() -> {
binding.etSupervisorContact.showSnackBar(getString(R.string.please_enter_supervisor_contact_number))
}
binding.etSupervisorAuthority.text.toString().isEmpty() -> {
binding.etSupervisorAuthority.showSnackBar(getString(R.string.please_enter_supervisor_authority_mosque))
}
binding.etBuildingCondition.text.toString().isEmpty() -> {
binding.etBuildingCondition.showSnackBar(getString(R.string.please_enter_building_condition))
}
binding.etMosqueArea.text.toString().isEmpty() -> {
binding.etMosqueArea.showSnackBar(getString(R.string.please_enter_mosque_area))
}
binding.etApproximateNumber.text.toString().isEmpty() -> {
binding.etApproximateNumber.showSnackBar(getString(R.string.please_enter_approximate_number_worshippers))
}
image.isEmpty() -> {
binding.rvImage.showSnackBar(getString(R.string.please_select_image))
}
isConnectedToInternet(requireActivity(), true) -> {
val hashMap = HashMap<String, RequestBody>()
hashMap["name"] = getRequestBody(binding.etName.text.toString())
hashMap["location"] = getRequestBody(binding.etLocation.text.toString())
hashMap["supervisor_name"] = getRequestBody(binding.etSupervisorAuthority.text.toString())
hashMap["supervisor_phone_number"] = getRequestBody(binding.etSupervisorContact.text.toString())
hashMap["site_condition"] = getRequestBody(binding.etBuildingCondition.text.toString())
hashMap["area"] = getRequestBody(binding.etMosqueArea.text.toString())
//hashMap["women_prayer_area"] = binding.wom.text.toString()
hashMap["total_capacity"] = getRequestBody(binding.etApproximateNumber.text.toString())
//hashMap["total_restrooms"] = binding.etPassword.text.toString()
// val body: RequestBody = fileToUpload?.asRequestBody("image/*".toMediaType())!!
// hashMap["image\"; fileName=\"" + fileToUpload?.name] = body*/
// viewModel.addSites(hashMap)
}
}
}
binding.rvImage.setOnClickListener {
showImageDialog();
}
cameraLauncher = registerForActivityResult(ActivityResultContracts.TakePicture()) { success ->
if (success) {
imageUri?.let {
// Handle image from camera
binding.rvImage.gone()
binding.ivSetImage.setImageURI(imageUri)
binding.ivCloseImage.visible()
}
}
}
galleryLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
uri?.let {
binding.llUploadImage.gone()
binding.ivSetImage.visible()
Glide.with(this).load(imageUri).into(binding.ivSetImage)
binding.ivCloseImage.visible()
}
}
binding.ivCloseImage.setOnClickListener {
binding.llUploadImage.visible()
binding.ivSetImage.visible()
Glide.with(this).load(imageUri).into(binding.ivSetImage)
binding.ivCloseImage.visible()
}
// Permission launcher
permissionLauncher = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
if (permissions[Manifest.permission.CAMERA] == true) {
openCamera()
} else {
Toast.makeText(requireContext(), "Camera permission denied", Toast.LENGTH_SHORT).show()
}
}
}
private fun bindObservers() {
viewModel.sites.observe(requireActivity(), Observer {
it ?: return@Observer
when (it.status) {
Status.SUCCESS -> {
findNavController().popBackStack();
progressDialog.setLoading(false)
}
Status.ERROR -> {
progressDialog.setLoading(false)
ApisRespHandler.handleError(it.error, requireActivity())
}
Status.LOADING -> {
progressDialog.setLoading(true)
}
}
})
}
fun showImageDialog() {
val dialog: Dialog = Dialog(requireActivity())
val view = SelectPhotoBinding.inflate(layoutInflater)
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
dialog.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
dialog.setContentView(view.root)
view.tvGallery.setOnClickListener {
galleryLauncher.launch("image/*")
dialog.dismiss()
}
view.tvCamera.setOnClickListener {
permissionLauncher.launch(arrayOf(Manifest.permission.CAMERA))
dialog.dismiss()
}
dialog.show()
}
private fun openCamera() {
imageUri = FileProvider.getUriForFile(
requireContext(),
"${requireContext().packageName}.provider",
createImageFile()
)
cameraLauncher.launch(imageUri!!)
}
private fun createImageFile(): File {
val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
val fileName = "JPEG_${timeStamp}_"
val storageDir = requireContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES)
return File.createTempFile(fileName, ".jpg", storageDir)
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -0,0 +1,50 @@
package com.example.fieldagent.ui.addsite
import androidx.lifecycle.ViewModel
import com.example.fieldagent.data.apis.WebService
import com.example.fieldagent.data.models.responses.UserData
import com.example.fieldagent.data.network.responseUtil.ApiResponse
import com.example.fieldagent.data.network.responseUtil.ApiUtils
import com.example.fieldagent.data.network.responseUtil.Resource
import com.example.fieldagent.di.SingleLiveEvent
import dagger.hilt.android.lifecycle.HiltViewModel
import okhttp3.RequestBody
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import javax.inject.Inject
@HiltViewModel
class AddSiteViewModel @Inject constructor(private val webService: WebService) : ViewModel() {
val sites by lazy { SingleLiveEvent<Resource<UserData>>() }
fun addSites(hashMap: HashMap<String, RequestBody>) {
sites.value = Resource.loading()
webService.createInspections(hashMap)
.enqueue(object : Callback<UserData> {
override fun onResponse(call: Call<UserData>,
response: Response<UserData>
) {
if (response.isSuccessful) {
sites.value = Resource.success(response.body())
} else {
sites.value = Resource.error(
ApiUtils.getError(response.code(),
response.errorBody()?.string()))
}
}
override fun onFailure(call: Call<UserData>, throwable: Throwable) {
sites.value = Resource.error(ApiUtils.failure(throwable))
}
})
}
}

View file

@ -7,6 +7,7 @@ import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
@ -21,6 +22,7 @@ import com.example.fieldagent.R
import com.example.fieldagent.databinding.FragmentHomeBinding
import com.example.fieldagent.ui.homescreen.adapter.HomeAdapter
import androidx.core.graphics.drawable.toDrawable
import androidx.core.view.isVisible
import androidx.fragment.app.viewModels
import com.consultantapp.data.network.responseUtil.Status
import com.example.fieldagent.data.network.ApisRespHandler
@ -36,11 +38,16 @@ import javax.inject.Inject
import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView
import com.example.fieldagent.data.models.responses.InspectionData
import com.example.fieldagent.data.models.responses.InspectionList
import com.example.fieldagent.data.models.responses.UserData
import com.example.fieldagent.databinding.PopLayoutBinding
import com.example.fieldagent.utils.AFTER
import com.example.fieldagent.utils.LIMIT_TEXT
import com.example.fieldagent.utils.PAGE_TEXT
import com.example.fieldagent.utils.PER_PAGE
import com.example.fieldagent.utils.PER_PAGE_LOAD
import com.example.fieldagent.utils.SEARCH
import com.example.fieldagent.utils.gone
import com.example.fieldagent.utils.hideShowView
import com.example.fieldagent.utils.isConnectedToInternet
@ -61,17 +68,21 @@ class HomeFragment : Fragment() {
lateinit var prefsManager: PrefsManager
private val viewModel: HomeViewModel by viewModels()
private lateinit var progressDialog: ProgressDialog
private var items = ArrayList<UserData>()
private var items = ArrayList<InspectionList>()
private var isLastPage = false
private var isFirstPage = true
private var isLoadingMoreItems = false
private var pageNumber = 1
private var searchJob: Job? = null
private var click: String ="all"
private var searchData: String =""
private var selectStatus: String =""
override fun onCreateView(
@ -100,8 +111,8 @@ class HomeFragment : Fragment() {
prefsManager.save(IS_LOGIN,true)
val hashMap = HashMap<String, String>()
hashMap["limit"] = "10"
hashMap["Page"] = "1"
hashMap[LIMIT_TEXT] = PER_PAGE_LOAD
hashMap[PAGE_TEXT] = PER_PAGE
viewModel.getInspectionList(hashMap);
}
@ -120,11 +131,13 @@ class HomeFragment : Fragment() {
}
binding.llLogoutBtn.setOnClickListener {
prefsManager.removeAll()
val intent = Intent(requireActivity(), LoginActivity::class.java)
startActivity(intent)
requireActivity().finish()
}
binding.ivFilter.setOnClickListener {
@ -142,12 +155,18 @@ class HomeFragment : Fragment() {
popupView.txtCompleted.setOnClickListener {
refreshPagination()
hitApi(false)
click="status"
selectStatus="true"
callStatusSearchApi("true","")
popupWindow.dismiss()
}
popupView.txtInProgress.setOnClickListener {
refreshPagination()
hitApi(false)
click="status"
selectStatus="false"
callStatusSearchApi("false","")
popupWindow.dismiss()
}
@ -160,6 +179,7 @@ class HomeFragment : Fragment() {
binding.swipeRefresh.setOnRefreshListener {
Log.e("hckkkk===>","swipes");
hitApi(true)
}
@ -168,7 +188,6 @@ class HomeFragment : Fragment() {
binding.rvList.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val layoutManager = binding.rvList.layoutManager as LinearLayoutManager
val totalItemCount = layoutManager.itemCount - 1
val lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition()
@ -188,8 +207,17 @@ class HomeFragment : Fragment() {
delay(300) // wait for user to stop typing (300ms)
val query = s.toString()
if (query.isNotBlank()) {
click="search"
searchData=query
refreshPagination()
hitApi(false)
callStatusSearchApi("false",query)
}else{
refreshPagination()
click="all"
val hashMap = HashMap<String, String>()
hashMap[LIMIT_TEXT] = PER_PAGE_LOAD
hashMap[PAGE_TEXT] = PER_PAGE
viewModel.getInspectionList(hashMap);
}
}
}
@ -200,24 +228,65 @@ class HomeFragment : Fragment() {
}
private fun refreshPagination(){
pageNumber=1;
isLastPage = false
isFirstPage = true
isLoadingMoreItems = false
}
private fun callStatusSearchApi( value:String,search:String){
val hashMap = HashMap<String, String>()
if(search.isEmpty())
{
hashMap["isCompleted"] = value
}else{
hashMap[SEARCH] = searchData
}
hashMap[LIMIT_TEXT] = PER_PAGE_LOAD
hashMap[PAGE_TEXT] = PER_PAGE
viewModel.getInspectionList(hashMap);
}
private fun hitApi(firstHit: Boolean) {
if (isConnectedToInternet(requireContext(), true)) {
if (firstHit) {
pageNumber=1
isFirstPage = true
isLastPage = false
}
val hashMap = HashMap<String, String>()
if (!isFirstPage && items.isNotEmpty())
// hashMap[AFTER] = items[items.size - 1].id ?: ""
{
pageNumber++
hashMap[LIMIT_TEXT] = PER_PAGE_LOAD
hashMap[PAGE_TEXT] = pageNumber.toString()
if(click=="status")
{
hashMap["isCompleted"] = selectStatus
}else if(click=="search")
{
hashMap[SEARCH] = searchData
}
}else{
if(click=="status")
{
hashMap["isCompleted"] = selectStatus
}else if(click=="search")
{
hashMap[SEARCH] = searchData
}
hashMap[LIMIT_TEXT] = PER_PAGE_LOAD
hashMap[PAGE_TEXT] = PER_PAGE
}
hashMap[PER_PAGE] = PER_PAGE_LOAD.toString()
viewModel.getInspectionList(hashMap)
} else
@ -233,8 +302,8 @@ class HomeFragment : Fragment() {
isLoadingMoreItems = false
// val tempList = it.data?.notifications ?: emptyList()
val tempList=ArrayList<UserData>()
val tempList = it.data?.data?.inspections ?: emptyList()
if (isFirstPage) {
isFirstPage = false
items.clear()
@ -248,11 +317,13 @@ class HomeFragment : Fragment() {
adapter.notifyItemRangeInserted(oldSize, items.size)
}
isLastPage = tempList.size < PER_PAGE_LOAD
isLastPage = tempList.size < PER_PAGE_LOAD.toInt()
/* if(click!="search"){
adapter.setAllItemsLoaded(isLastPage)
}*/
binding.clNoData.rootView.hideShowView(items.isEmpty())
binding.clNoData.hideShowView(items.isEmpty())
}
Status.ERROR -> {
isLoadingMoreItems = false
@ -263,7 +334,7 @@ class HomeFragment : Fragment() {
ApisRespHandler.handleError(it.error, requireActivity())
}
Status.LOADING -> {
if (!isLoadingMoreItems && !binding.swipeRefresh.isRefreshing)
if (!isLoadingMoreItems && !binding.swipeRefresh.isRefreshing && !binding.clNoData.isVisible && items.isEmpty())
binding.clLoader.root.visible()
}
}
@ -275,6 +346,11 @@ class HomeFragment : Fragment() {
val item = items[pos]
}
fun clickDeleteItem(pos: Int) {
items.removeAt(pos)
adapter.notifyDataSetChanged()
}
override fun onDestroyView() {

View file

@ -2,6 +2,8 @@ package com.example.fieldagent.ui.homescreen
import androidx.lifecycle.ViewModel
import com.example.fieldagent.data.apis.WebService
import com.example.fieldagent.data.models.responses.InspectionData
import com.example.fieldagent.data.models.responses.InspectionList
import com.example.fieldagent.data.models.responses.UserData
import com.example.fieldagent.data.network.responseUtil.ApiResponse
import com.example.fieldagent.data.network.responseUtil.ApiUtils
@ -17,19 +19,19 @@ import javax.inject.Inject
@HiltViewModel
class HomeViewModel @Inject constructor(private val webService: WebService) : ViewModel() {
val inspections by lazy { SingleLiveEvent<Resource<UserData>>() }
val inspections by lazy { SingleLiveEvent<Resource<InspectionData>>() }
fun getInspectionList(hashMap: HashMap<String, String>) {
inspections.value = Resource.loading()
webService.inspectionsList(hashMap)
.enqueue(object : Callback<ApiResponse<UserData>> {
.enqueue(object : Callback<InspectionData> {
override fun onResponse(call: Call<ApiResponse<UserData>>,
response: Response<ApiResponse<UserData>>
override fun onResponse(call: Call<InspectionData>,
response: Response<InspectionData>
) {
if (response.isSuccessful) {
inspections.value = Resource.success(response.body()?.data)
inspections.value = Resource.success(response.body())
} else {
inspections.value = Resource.error(
@ -38,7 +40,7 @@ class HomeViewModel @Inject constructor(private val webService: WebService) : Vi
}
}
override fun onFailure(call: Call<ApiResponse<UserData>>, throwable: Throwable) {
override fun onFailure(call: Call<InspectionData>, throwable: Throwable) {
inspections.value = Resource.error(ApiUtils.failure(throwable))
}

View file

@ -10,15 +10,18 @@ import androidx.navigation.findNavController
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.RecyclerView
import com.example.fieldagent.R
import com.example.fieldagent.data.models.responses.InspectionData
import com.example.fieldagent.data.models.responses.InspectionList
import com.example.fieldagent.data.models.responses.UserData
import com.example.fieldagent.databinding.FragmentHomeBinding
import com.example.fieldagent.databinding.HomeAdapterBinding
import com.example.fieldagent.databinding.ItemPagingLoaderBinding
import com.example.fieldagent.ui.homescreen.HomeFragment
import com.example.fieldagent.utils.DateUtils.getTimeAgo
import com.example.fieldagent.utils.LoadingStatus.ITEM
import com.example.fieldagent.utils.LoadingStatus.LOADING
class HomeAdapter(private val fragment: HomeFragment,private val items: ArrayList<UserData>) :
class HomeAdapter(private val fragment: HomeFragment,private val items: ArrayList<InspectionList>) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var allItemsLoaded = true
@ -48,15 +51,21 @@ class HomeAdapter(private val fragment: HomeFragment,private val items: ArrayLi
binding.clMain.setOnClickListener {
fragment.clickItem(bindingAdapterPosition)
}
binding.ivDelete.setOnClickListener {
fragment.clickDeleteItem(bindingAdapterPosition)
}
}
fun bind(item: UserData) = with(binding) {
/*tvName.text = item.message
loadImage("tag",binding.ivPic, item.form_user?.profile_image,
R.drawable.image_placeholder)
tvCallDuration.text = getTimeAgo(item.created_at)*/
fun bind(item: InspectionList) = with(binding) {
binding.txtName.text=item.name.toString()
binding.txtLocation.text=item.location.toString()
binding.txtTime.text=getTimeAgo(item.createdAt.toString())
binding.txtPayment.text="$ 0"
binding.txtStatus.text = if (item.isCompleted == true) {
binding.root.context.getString(R.string.completed)
} else {
binding.root.context.getString(R.string.in_progress)
}
}
}
@ -67,35 +76,3 @@ class HomeAdapter(private val fragment: HomeFragment,private val items: ArrayLi
allItemsLoaded = allLoaded
}
}
/*(var homes: List<HomeFragment.Home>) : RecyclerView.Adapter<HomeAdapter.HomeViewHolder>() {
class HomeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val nameText: TextView = itemView.findViewById(R.id.txtName)
val locationText: TextView = itemView.findViewById(R.id.txtLocation)
val timeText: TextView = itemView.findViewById(R.id.txtTime)
val moneyText: TextView = itemView.findViewById(R.id.txtPayment)
val statusText: TextView = itemView.findViewById(R.id.txtStatus)
val viewClick: RelativeLayout = itemView.findViewById(R.id.rlView)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HomeViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.home_adapter, parent, false)
return HomeViewHolder(view)
}
override fun onBindViewHolder(holder: HomeViewHolder, position: Int) {
val user = homes[position]
holder.nameText.text = user.name
holder.locationText.text = user.address
holder.timeText.text = user.time
holder.moneyText.text = user.payment
holder.statusText.text = user.status
holder.viewClick.setOnClickListener {view->
view.findNavController().navigate(R.id.damageListFragment)
}
}
override fun getItemCount(): Int = homes.size
}*/

View file

@ -8,13 +8,15 @@ import android.util.Patterns
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import com.consultantapp.data.network.responseUtil.Status
import com.example.fieldagent.R
import com.example.fieldagent.data.models.responses.UserData
import com.example.fieldagent.data.network.ApisRespHandler
import com.example.fieldagent.databinding.ActivityLoginBinding
import com.example.fieldagent.ui.homescreen.HomeActivity
import androidx.lifecycle.Observer
import com.example.fieldagent.utils.PrefsManager
import com.example.fieldagent.utils.TOKEN
import com.example.fieldagent.utils.USER_DATA
import com.example.fieldagent.utils.dialogs.ProgressDialog
import com.example.fieldagent.utils.isConnectedToInternet
@ -79,9 +81,10 @@ class LoginActivity : AppCompatActivity() {
when (it.status) {
Status.SUCCESS -> {
progressDialog.setLoading(false)
// prefsManager.save(USER_DATA, it.data?.data)
prefsManager.saveString(TOKEN,it.data?.data?.tokens?.accessToken.toString())
prefsManager.save(USER_DATA, it.data)
val intent = Intent(this, HomeActivity::class.java)
startActivity(intent)
finish()

View file

@ -1,6 +1,7 @@
package com.example.fieldagent.ui.login
import android.content.Intent
import android.util.Log
import androidx.core.content.ContextCompat.startActivity
import androidx.lifecycle.ViewModel
import com.example.fieldagent.data.apis.WebService
@ -25,13 +26,13 @@ class LoginViewModel @Inject constructor(private val webService: WebService) : V
login.value = Resource.loading()
webService.login(hashMap)
.enqueue(object : Callback<ApiResponse<UserData>> {
.enqueue(object : Callback<UserData> {
override fun onResponse(call: Call<ApiResponse<UserData>>,
response: Response<ApiResponse<UserData>>
override fun onResponse(call: Call<UserData>,
response: Response<UserData>
) {
if (response.isSuccessful) {
login.value = Resource.success(response.body()?.data)
login.value = Resource.success(response.body())
} else {
login.value = Resource.error(
@ -40,7 +41,7 @@ class LoginViewModel @Inject constructor(private val webService: WebService) : V
}
}
override fun onFailure(call: Call<ApiResponse<UserData>>, throwable: Throwable) {
override fun onFailure(call: Call<UserData>, throwable: Throwable) {
login.value = Resource.error(ApiUtils.failure(throwable))
}

View file

@ -3,12 +3,17 @@ package com.example.fieldagent.utils
const val USER_DATA = "userData"
const val TOKEN = "token"
const val IS_LOGIN = "isLogin"
const val AFTER = "after"
const val BEFORE = "before"
const val PER_PAGE = "per_page"
const val PER_PAGE_LOAD = 10
const val PER_PAGE = "1"
const val LIMIT_TEXT = "limit"
const val SEARCH = "search"
const val PAGE_TEXT = "page"
const val PER_PAGE_LOAD = "10"
object LoadingStatus {

View file

@ -0,0 +1,66 @@
package com.example.fieldagent.utils
import android.text.format.DateUtils
import java.text.SimpleDateFormat
import java.util.*
object DateUtils {
val utcFormat = SimpleDateFormat(DateFormat.UTC_FORMAT_NORMAL, Locale.ENGLISH)
fun getTimeAgo(createdAt: String?): String {
if (createdAt == null) return ""
return try {
val utcFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault())
utcFormat.timeZone = TimeZone.getTimeZone("UTC")
val pastTime = utcFormat.parse(createdAt)?.time ?: return ""
val now = System.currentTimeMillis()
val seconds = (now - pastTime) / 1000
val minutes = seconds / 60
val hours = minutes / 60
val days = hours / 24
return when {
seconds < 60 -> "$seconds seconds ago"
minutes < 60 -> "$minutes minutes ago"
hours < 24 -> "$hours hours ago"
days < 7 -> "$days days ago"
else -> {
val outputFormat = SimpleDateFormat("dd MMM yyyy", Locale.getDefault())
outputFormat.format(Date(pastTime))
}
}
} catch (e: Exception) {
e.printStackTrace()
""
}
}
}
object DateFormat {
const val DATE_FORMAT = "yyyy-MM-dd"
const val DATE_TIME_FORMAT = "MMM dd, yyyy · hh:mm a"
const val DAY_DATE_FORMAT = "EEE · MMM dd, yyyy"
const val TIME_FORMAT = "hh:mm a"
const val TIME_FORMAT_24 = "HH:mm"
const val MON_DATE_YEAR = "MMM dd, yyyy"
const val MON_DATE = "MMM dd"
const val DATE_FORMAT_SLASH_YEAR = "dd/MM/yyyy"
const val UTC_FORMAT_NORMAL = "yyyy-MM-dd HH:mm:ss"
const val UTC_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
const val DATE = "dd"
const val MONTH = "MM"
const val YEAR = "yyyy"
const val HH_24 = "HH"
const val MM = "mm"
}

View file

@ -7,8 +7,8 @@ import android.widget.Toast
import androidx.core.content.ContextCompat
import com.example.fieldagent.R
import com.google.android.material.snackbar.Snackbar
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
fun View.gone() {
@ -28,7 +28,9 @@ fun View.hideShowView(listIsEmpty: Boolean) {
else View.GONE
}
fun getRequestBody(string: String?): RequestBody {
return RequestBody.create("text/plain".toMediaTypeOrNull(), string ?: "")
}
fun View.showSnackBar(msg: String) {
@ -45,6 +47,7 @@ fun View.showSnackBar(msg: String) {
} catch (e: Exception) {
e.printStackTrace()
}
}
fun Context.longToast(text: CharSequence) {
Toast.makeText(this, text, Toast.LENGTH_LONG).show()

View file

@ -15,7 +15,7 @@ class PrefsManager @Inject constructor(private val preferences: SharedPreference
private lateinit var instance: PrefsManager
fun get(): PrefsManager = instance }
fun save(@PrefKey key: String, value: String) {
fun saveString(@PrefKey key: String, value: String) {
preferences.edit().putString(key, value).apply()
}

View file

@ -411,20 +411,28 @@
android:layout_marginTop="@dimen/dp_4"
android:background="@drawable/line_spce_line"
android:layout_marginBottom="@dimen/dp_20"
>
<ImageView
android:layout_width="@dimen/dp_20"
android:layout_height="@dimen/dp_20"
android:id="@+id/ivCloseImage"
android:layout_width="@dimen/dp_40"
android:layout_height="@dimen/dp_40"
android:src="@drawable/close_circle"
android:layout_alignParentEnd="true"
android:layout_marginTop="@dimen/dp_8"
android:layout_marginEnd="@dimen/dp_8"
android:visibility="gone"
android:padding="@dimen/dp_8"
/>
<ImageView
android:id="@+id/ivSetImage"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_160"
android:scaleType="center"
/>
<LinearLayout
android:id="@+id/llUploadImage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
@ -453,8 +461,12 @@
</RelativeLayout>
<Button
android:id="@+id/btnSigIn"
android:id="@+id/btnAdd"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="@id/leftGuide"

View file

@ -59,7 +59,9 @@
android:id="@+id/ivDelete"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.07"
android:paddingStart="@dimen/dp_10"
android:layout_weight="0.1"
android:src="@drawable/delete"/>
</LinearLayout>
@ -124,7 +126,7 @@
android:layout_marginStart="@dimen/dp_4"
android:textSize="@dimen/sp_12"
android:fontFamily="@font/montserratregular"
android:layout_marginTop="@dimen/dp_4"
android:layout_marginTop="3dp"
/>

View file

@ -11,6 +11,7 @@
android:layout_width="@dimen/dp_24"
android:layout_height="@dimen/dp_24"
android:layout_gravity="center"
android:indeterminateTint="@color/main_color"
android:progressDrawable="@color/main_color"
android:progressTint="@color/main_color"
app:layout_constraintBottom_toBottomOf="parent"

View file

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@color/white">
<RelativeLayout
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:actionBarSize"
android:background="@color/main_color"
app:contentInsetStart="0dp">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tvdialog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:gravity="center"
android:fontFamily="@font/montserratsemibold"
android:text="@string/select"
android:textColor="@color/white" />
</RelativeLayout>
<LinearLayout
android:layout_below="@id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="2">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tvGallery"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="@dimen/dp_16"
android:layout_margin="@dimen/dp_4"
android:text="@string/gallery"
android:fontFamily="@font/montserratmedium"
android:textColor="@color/main_color"
android:textAlignment="center" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tvCamera"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="@dimen/dp_16"
android:layout_margin="@dimen/dp_4"
android:text="@string/camera"
android:fontFamily="@font/montserratmedium"
android:textAlignment="center"
android:textColor="@color/main_color"/>
</LinearLayout>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tvPdf"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:layout_below="@id/toolbar"
android:text="Upload Document"
android:visibility="gone"
android:textAlignment="center"
android:textColor="@android:color/black"
/>
</RelativeLayout>

View file

@ -127,6 +127,10 @@
<string name="alert">Alert</string>
<string name="logout">Logout</string>
<string name="no_inspection_data">No Inspection Data</string>
<string name="please_select_image">Please select image</string>
<string name="select">Select</string>
<string name="gallery">Gallery</string>
<string name="camera">Camera</string>
<string-array name="availability">

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-cache-path
name="external_cache_files"
path="." />
<external-files-path
name="external_files_files"
path="." />
<external-path
name="external_files"
path="." />
</paths>

View file

@ -24,6 +24,7 @@ timber = "5.0.1"
okhttp = "5.0.0-alpha.14"
loggingInterceptor = "5.0.0-alpha.14"
swiperefreshlayout = "1.2.0-beta01"
glide = "5.0.0-rc01"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@ -55,6 +56,7 @@ timber = { group = "com.jakewharton.timber", name = "timber", version.ref = "tim
okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp" }
logging-interceptor = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "loggingInterceptor" }
androidx-swiperefreshlayout = { group = "androidx.swiperefreshlayout", name = "swiperefreshlayout", version.ref = "swiperefreshlayout" }
glide = { group = "com.github.bumptech.glide", name = "glide", version.ref = "glide" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }