refresh token used

This commit is contained in:
Aryankc2 2025-05-05 18:11:41 +05:30
parent dfe3f2116f
commit cf8776568d
17 changed files with 695 additions and 512 deletions

View file

@ -61,6 +61,11 @@ dependencies {
implementation(libs.androidx.swiperefreshlayout)
implementation(libs.glide)
implementation(libs.play.services.location)
implementation(libs.androidx.camera.core)
implementation(libs.androidx.camera.camera2)
implementation(libs.androidx.camera.lifecycle)
implementation(libs.androidx.camera.view)
implementation(libs.androidx.camera.extensions)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)

View file

@ -54,6 +54,7 @@
android:exported="true"
android:windowSoftInputMode="adjustResize"
android:configChanges="orientation|screenSize"
android:launchMode="singleTop"
android:screenOrientation="portrait"
/>

View file

@ -1,5 +1,6 @@
package com.example.fieldagent.data.apis
import TokenModel
import com.example.fieldagent.data.models.responses.*
import com.example.fieldagent.data.network.responseUtil.ApiResponse
@ -18,6 +19,7 @@ interface WebService {
private const val CATEGORY = "categories"
private const val SELECT_CATEGORY = "categories"
private const val USER = "users"
private const val REFRESH_TOKEN = "auth/refresh-token"
@ -78,4 +80,8 @@ interface WebService {
@PUT("$USER/{id}")
fun updateProfile(@Path("id") id: String,@FieldMap hashMap: HashMap<String, String>): Call<SimpleResponseData>
@POST(REFRESH_TOKEN)
fun refreshToken(): Call<TokenModel>
}

View file

@ -0,0 +1,15 @@
data class TokenModel (
val status: Long? = null,
val success: Boolean? = null,
val message: String? = null,
val data: Data? = null
)
data class Data (
val tokens: Tokens? = null
)
data class Tokens (
val accessToken: String? = null
)

View file

@ -4,7 +4,9 @@ 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.CALL_TOKEN
import com.example.fieldagent.utils.PrefsManager
import com.example.fieldagent.utils.REFRESH_TOKEN
import com.example.fieldagent.utils.TOKEN
import com.example.fieldagent.utils.USER_DATA
import com.google.gson.Gson
@ -66,11 +68,18 @@ object NetworkModule {
.addHeader("timezone", TimeZone.getDefault().id)
val accessToken = prefsManager.getString(TOKEN,"")
val refreshToken = prefsManager.getString(REFRESH_TOKEN,"")
val callToken = prefsManager.getString(CALL_TOKEN,"")
if (!accessToken.isNullOrEmpty())
requestBuilder.addHeader("authorization", "Bearer $accessToken")
if (callToken=="yes")
requestBuilder.addHeader("X-Refresh-Token", "$refreshToken")
request=requestBuilder.build()
chain.proceed(request)

View file

@ -4,6 +4,7 @@ import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity.RESULT_OK
import android.app.Dialog
import android.content.ContentValues
import android.content.Context
import android.content.Intent
import android.content.IntentSender
@ -18,6 +19,7 @@ import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.provider.MediaStore
import android.provider.Settings
import android.text.Editable
import android.text.TextWatcher
@ -35,6 +37,11 @@ import androidx.activity.result.IntentSenderRequest
import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresPermission
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageCapture
import androidx.camera.core.ImageCaptureException
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
@ -118,6 +125,9 @@ class AddSiteFragment : Fragment() {
private lateinit var fusedLocationClient: FusedLocationProviderClient
private lateinit var locationPermissionLauncher: ActivityResultLauncher<Array<String>>
private var imageCapture: ImageCapture? = null
private lateinit var cameraProvider: ProcessCameraProvider
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
@ -189,15 +199,19 @@ class AddSiteFragment : Fragment() {
cameraLauncher = registerForActivityResult(ActivityResultContracts.TakePicture()) { success ->
if (success) {
imageUri?.let {
// Handle image from camerax
binding.llUploadImage.gone()
binding.cardImage.visible()
binding.ivSetImage.setImageURI(imageUri)
binding.ivCloseImage.visible()
fileToUpload=uriToFile(imageUri!!,requireActivity());
lifecycleScope.launch {
delay(300) // This helps avoid Handler-on-dead-thread on some OEMs
imageUri?.let {
binding.llUploadImage.gone()
binding.cardImage.visible()
binding.ivSetImage.setImageURI(imageUri)
binding.ivCloseImage.visible()
fileToUpload = uriToFile(imageUri!!, requireActivity())
}
}
}
}
@ -246,7 +260,7 @@ class AddSiteFragment : Fragment() {
// 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()
}
@ -481,8 +495,10 @@ class AddSiteFragment : Fragment() {
view.tvCamera.setOnClickListener {
permissionLauncher.launch(arrayOf(Manifest.permission.CAMERA))
// startCameraX();
// permissionLauncher.launch(arrayOf(Manifest.permission.CAMERA))
openCamera()
dialog.dismiss()
}
dialog.show()
@ -490,16 +506,28 @@ class AddSiteFragment : Fragment() {
private fun openCamera() {
imageUri = FileProvider.getUriForFile(
/* imageUri = FileProvider.getUriForFile(
requireContext(),
"${requireContext().packageName}.provider",
createImageFile()
)
)*/
imageUri=createImageUri()
cameraLauncher.launch(imageUri!!)
}
private fun createImageUri(): Uri? {
val contentValues = ContentValues().apply {
put(MediaStore.Images.Media.DISPLAY_NAME, "IMG_${System.currentTimeMillis()}.jpg")
put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
}
return requireContext().contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
}
private fun createImageFile(): File {

View file

@ -226,7 +226,7 @@ class DamageListFragment : Fragment() {
// setUpPdf()
val url = DOWNLOAD_URL+hashCode
val url = DOWNLOAD_URL+hashCode+"/"
val downloadsFolder = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
val fileName = url.substringAfterLast('/')+".pdf"
val destinationFile = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), fileName)
@ -612,7 +612,7 @@ class DamageListFragment : Fragment() {
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://example.com/") // Placeholder, overridden by @Url
.baseUrl(fileUrl) // Placeholder, overridden by @Url
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()

View file

@ -43,13 +43,16 @@ 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.data.network.responseUtil.AppError
import com.example.fieldagent.databinding.PopLayoutBinding
import com.example.fieldagent.utils.AFTER
import com.example.fieldagent.utils.CALL_TOKEN
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.TOKEN
import com.example.fieldagent.utils.gone
import com.example.fieldagent.utils.hideShowView
import com.example.fieldagent.utils.isConnectedToInternet
@ -116,7 +119,7 @@ class HomeFragment : Fragment() {
private fun initialize(){
prefsManager.save(IS_LOGIN,true)
prefsManager.saveString(CALL_TOKEN,"no")
if (viewModel.inspections.value?.data?.data?.inspections.isNullOrEmpty()) {
val hashMap = HashMap<String, String>()
hashMap[LIMIT_TEXT] = PER_PAGE_LOAD
@ -350,8 +353,18 @@ class HomeFragment : Fragment() {
adapter.setAllItemsLoaded(true)
binding.swipeRefresh.isRefreshing = false
binding.clLoader.root.gone()
ApisRespHandler.handleError(it.error, requireActivity())
if (it.error is AppError.ApiUnauthorized)
{
prefsManager.saveString(CALL_TOKEN,"yes")
viewModel.getRefreshToken()
}else{
binding.clLoader.root.gone()
ApisRespHandler.handleError(it.error, requireActivity())
}
}
Status.LOADING -> {
Log.e("Checkkkkkkksds==in loading=>","${items.size}")
@ -391,6 +404,33 @@ class HomeFragment : Fragment() {
}
}
})
viewModel.refreshToken.observe(requireActivity(), Observer {
it ?: return@Observer
when (it.status) {
Status.SUCCESS -> {
// binding.clLoader.root.gone()
prefsManager.saveString(CALL_TOKEN,"no")
prefsManager.saveString(TOKEN,it.data?.data?.tokens?.accessToken.toString())
refreshPagination()
val hashMap = HashMap<String, String>()
hashMap[LIMIT_TEXT] = PER_PAGE_LOAD
hashMap[PAGE_TEXT] = PER_PAGE
viewModel.getInspectionList(hashMap)
}
Status.ERROR -> {
binding.clLoader.root.gone()
ApisRespHandler.handleError(it.error, requireActivity())
}
Status.LOADING -> {
binding.clLoader.root.visible()
}
}
})
}

View file

@ -1,5 +1,6 @@
package com.example.fieldagent.ui.homescreen
import TokenModel
import androidx.lifecycle.ViewModel
import com.example.fieldagent.data.apis.WebService
import com.example.fieldagent.data.models.responses.InspectionData
@ -19,6 +20,7 @@ class HomeViewModel @Inject constructor(private val webService: WebService) : Vi
val inspections by lazy { SingleLiveEvent<Resource<InspectionData>>() }
val delete by lazy { SingleLiveEvent<Resource<SimpleResponseData>>() }
val refreshToken by lazy { SingleLiveEvent<Resource<TokenModel>>() }
fun getInspectionList(hashMap: HashMap<String, String>) {
inspections.value = Resource.loading()
@ -47,6 +49,33 @@ class HomeViewModel @Inject constructor(private val webService: WebService) : Vi
}
fun getRefreshToken() {
refreshToken.value = Resource.loading()
webService.refreshToken()
.enqueue(object : Callback<TokenModel> {
override fun onResponse(call: Call<TokenModel>,
response: Response<TokenModel>
) {
if (response.isSuccessful) {
refreshToken.value = Resource.success(response.body())
} else {
refreshToken.value = Resource.error(
ApiUtils.getError(response.code(),
response.errorBody()?.string()))
}
}
override fun onFailure(call: Call<TokenModel>, throwable: Throwable) {
refreshToken.value = Resource.error(ApiUtils.failure(throwable))
}
})
}
fun deleteInspection(id:String) {
delete.value = Resource.loading()

View file

@ -20,6 +20,7 @@ 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.REFRESH_TOKEN
import com.example.fieldagent.utils.TOKEN
import com.example.fieldagent.utils.USER_DATA
import com.example.fieldagent.utils.dialogs.ProgressDialog
@ -107,9 +108,7 @@ class LoginActivity : AppCompatActivity() {
prefsManager.saveString(USER_DATA,jsonString)
prefsManager.saveString(TOKEN,it.data?.data?.tokens?.accessToken.toString())
prefsManager.saveString(REFRESH_TOKEN,it.data?.data?.tokens?.refreshToken.toString())
val intent = Intent(this, HomeActivity::class.java)
startActivity(intent)

View file

@ -4,6 +4,8 @@ package com.example.fieldagent.utils
const val USER_DATA = "userData"
const val TOKEN = "token"
const val REFRESH_TOKEN = "refreshToken"
const val CALL_TOKEN = "no"
const val IS_LOGIN = "isLogin"
const val AFTER = "after"

File diff suppressed because it is too large Load diff

View file

@ -233,7 +233,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/password"
android:text="@string/new_password"
android:fontFamily="@font/montserratregular"
android:layout_marginTop="@dimen/dp_16"
@ -260,7 +260,7 @@
android:textSize="@dimen/sp_14"
android:maxLines="1"
android:singleLine="true"
android:hint="@string/password"
android:hint="@string/new_password"
android:imeOptions="actionDone"
android:gravity="start"
android:fontFamily="@font/montserratregular"

View file

@ -109,7 +109,8 @@
<string name="contact_number_length_error">الرجاء إدخال رقم اتصال صالح يتكون من 7 إلى 11 رقمًا</string>
<string name="please_try_again_later">يرجى المحاولة مرة أخرى لاحقا</string>
<string name="please_enter_valid_password">يجب أن تتكون كلمة المرور من 6 أحرف على الأقل وتتضمن حرفًا كبيرًا واحدًا ورقمًا واحدًا وحرفًا خاصًا واحدًا</string>
<string name="new_password">كلمة المرور الجديدة</string>
<string name="please_enter_new_password">الرجاء إدخال كلمة المرور الجديدة</string>
<string-array name="availability">
<item>@string/yes</item>
<item>@string/no</item>

View file

@ -13,6 +13,8 @@
<string name="sign_in_to_continue">Sign In to Continue</string>
<string name="email_address">Email Address</string>
<string name="password">Password</string>
<string name="new_password">New Password</string>
<string name="please_enter_new_password">Please enter new password</string>
<string name="inspections">Inspections</string>
<string name="add_site">Add Site</string>
<string name="add">Add</string>

View file

@ -26,6 +26,11 @@ loggingInterceptor = "5.0.0-alpha.14"
swiperefreshlayout = "1.2.0-beta01"
glide = "5.0.0-rc01"
playServicesLocation = "21.3.0"
cameraCore = "1.5.0-alpha06"
cameraCamera2 = "1.5.0-alpha06"
cameraLifecycle = "1.5.0-alpha06"
cameraView = "1.5.0-alpha06"
cameraExtensions = "1.5.0-alpha06"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@ -59,6 +64,11 @@ logging-interceptor = { group = "com.squareup.okhttp3", name = "logging-intercep
androidx-swiperefreshlayout = { group = "androidx.swiperefreshlayout", name = "swiperefreshlayout", version.ref = "swiperefreshlayout" }
glide = { group = "com.github.bumptech.glide", name = "glide", version.ref = "glide" }
play-services-location = { group = "com.google.android.gms", name = "play-services-location", version.ref = "playServicesLocation" }
androidx-camera-core = { group = "androidx.camera", name = "camera-core", version.ref = "cameraCore" }
androidx-camera-camera2 = { group = "androidx.camera", name = "camera-camera2", version.ref = "cameraCamera2" }
androidx-camera-lifecycle = { group = "androidx.camera", name = "camera-lifecycle", version.ref = "cameraLifecycle" }
androidx-camera-view = { group = "androidx.camera", name = "camera-view", version.ref = "cameraView" }
androidx-camera-extensions = { group = "androidx.camera", name = "camera-extensions", version.ref = "cameraExtensions" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }