project added

This commit is contained in:
Aryankc2 2025-04-24 09:56:13 +05:30
parent 66c22d375c
commit 76eaed7ba2
153 changed files with 6452 additions and 0 deletions

15
.gitignore vendored Normal file
View file

@ -0,0 +1,15 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties

3
.idea/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

1
.idea/.name Normal file
View file

@ -0,0 +1 @@
Field Agent

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AndroidProjectSystem">
<option name="providerId" value="com.android.tools.idea.GradleProjectSystem" />
</component>
</project>

6
.idea/compiler.xml Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="21" />
</component>
</project>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetSelector">
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
</selectionStates>
</component>
</project>

19
.idea/gradle.xml Normal file
View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="CHOOSE_PER_TEST" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

6
.idea/kotlinc.xml Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="2.1.20" />
</component>
</project>

10
.idea/migrations.xml Normal file
View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>

9
.idea/misc.xml Normal file
View file

@ -0,0 +1,9 @@
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
<option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
<option value="com.intellij.execution.junit.PatternConfigurationProducer" />
<option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
<option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
<option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
</set>
</option>
</component>
</project>

6
.idea/vcs.xml Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

1
app/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/build

79
app/build.gradle.kts Normal file
View file

@ -0,0 +1,79 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
alias(libs.plugins.hilt)
alias(libs.plugins.ksp)
}
android {
namespace = "com.example.fieldagent"
compileSdk = 35
defaultConfig {
applicationId = "com.example.fieldagent"
minSdk = 24
targetSdk = 35
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
buildFeatures {
viewBinding = true
}
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
implementation(libs.androidx.constraintlayout)
implementation(libs.androidx.navigation.fragment.ktx)
implementation(libs.androidx.navigation.ui.ktx)
implementation(libs.androidx.annotation)
implementation(libs.androidx.lifecycle.livedata.ktx)
implementation(libs.androidx.lifecycle.viewmodel.ktx)
implementation(libs.androidx.activity)
implementation(libs.androidx.fragment.ktx)
implementation(libs.androidx.recyclerview)
implementation(libs.timber)
implementation(libs.okhttp)
implementation(libs.logging.interceptor)
implementation(libs.androidx.swiperefreshlayout)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
implementation(libs.hilt.android)
ksp(libs.hilt.compiler)
//retrofit
implementation(libs.retrofit.core)
implementation(libs.retrofit.gson)
implementation(libs.retrofit.scalars)
implementation(libs.retrofit.rxjava2)
implementation(libs.kotlinx.coroutines.core)
implementation(libs.retrofit.coroutines.adapter)
}

21
app/proguard-rules.pro vendored Normal file
View file

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View file

@ -0,0 +1,24 @@
package com.example.fieldagent
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.example.fieldagent", appContext.packageName)
}
}

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name=".AgentApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.FieldAgent"
tools:targetApi="31">
<activity
android:name=".ui.SplashActivity"
android:exported="true"
android:theme="@style/Theme.FieldAgent"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ui.login.LoginActivity"
android:exported="true"/>
<activity
android:name=".ui.homescreen.HomeActivity"
android:exported="true" />
</application>
</manifest>

View file

@ -0,0 +1,14 @@
package com.example.fieldagent
import android.app.Application
import com.example.fieldagent.utils.PrefsManager
import dagger.hilt.android.HiltAndroidApp
import javax.inject.Inject
@HiltAndroidApp
class AgentApplication : Application() {
@Inject
lateinit var prefsManager: PrefsManager
}

View file

@ -0,0 +1,44 @@
package com.example.fieldagent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.navigation.fragment.findNavController
import com.example.fieldagent.databinding.FragmentFirstBinding
/**
* A simple [Fragment] subclass as the default destination in the navigation.
*/
class FirstFragment : Fragment() {
private var _binding: FragmentFirstBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentFirstBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.buttonFirst.setOnClickListener {
// findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -0,0 +1,59 @@
package com.example.fieldagent
import android.os.Bundle
import com.google.android.material.snackbar.Snackbar
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.navigateUp
import androidx.navigation.ui.setupActionBarWithNavController
import android.view.Menu
import android.view.MenuItem
import com.example.fieldagent.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
setSupportActionBar(binding.toolbar)
val navController = findNavController(R.id.nav_host_fragment_content_main)
appBarConfiguration = AppBarConfiguration(navController.graph)
setupActionBarWithNavController(navController, appBarConfiguration)
binding.fab.setOnClickListener { view ->
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null)
.setAnchorView(R.id.fab).show()
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.menu_main, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
return when (item.itemId) {
R.id.action_settings -> true
else -> super.onOptionsItemSelected(item)
}
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment_content_main)
return navController.navigateUp(appBarConfiguration)
|| super.onSupportNavigateUp()
}
}

View file

@ -0,0 +1,44 @@
package com.example.fieldagent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.navigation.fragment.findNavController
import com.example.fieldagent.databinding.FragmentSecondBinding
/**
* A simple [Fragment] subclass as the second destination in the navigation.
*/
class SecondFragment : Fragment() {
private var _binding: FragmentSecondBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentSecondBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.buttonSecond.setOnClickListener {
// findNavController().navigate(R.id.action_SecondFragment_to_FirstFragment)
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -0,0 +1,497 @@
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 retrofit2.Call
import retrofit2.http.DELETE
import retrofit2.http.GET
import retrofit2.http.PUT
import retrofit2.http.Path
import retrofit2.http.QueryMap
interface WebService {
companion object {
private const val LOGIN = "auth/login"
private const val INSPECTIONS_LIST = "inspections"
private const val CREATE_INSPECTION = "inspections"
private const val DELETE_INSPECTIONS = "subcategories"
private const val UPDATE_INSPECTIONS = "subcategories"
private const val DAMAGES = "Damages"
private const val COUNTRY_DATA = "/api/countrydata"
private const val PREFERENCES = "/api/master/preferences"
private const val UPDATE_NUMBER = "/api/update-phone"
private const val VERIFY_OTP = "/api/verify-otp"
private const val RESEND_OTP = "api/resend-otp"
private const val REGISTER = "/api/register"
private const val FORGOT_PASSWORD = "/api/forgot_password"
private const val CHANGE_PASSWORD = "/api/password-change"
private const val PROFILE_UPDATE = "/api/profile-update"
private const val LOGOUT = "/api/app_logout"
private const val SEND_SMS = "/api/send-sms"
private const val SEND_EMAIL_OTP = "/api/send-email-otp"
private const val EMAIL_VERIFY = "/api/email-verify"
private const val UPDATE_FCM_ID = "/api/update-fcm-id"
private const val CREATE_REQUEST = "/api/create-request"
private const val CONFIRM_REQUEST = "/api/confirm-request"
private const val ADD_CARD = "api/add-card"
private const val UPDATE_CARD = "/api/update-card"
private const val DELETE_CARD = "/api/delete-card"
private const val ADD_MONEY = "/api/add-money"
private const val ADD_REVIEW = "/api/add-review"
private const val REQUEST_USER_APPROVE = "/api/request-user-approve"
private const val COMPLETE_CHAT = "/api/complete-chat"
private const val UPLOAD_IMAGE = "/api/upload-image"
private const val FEEDS = "/api/feeds"
private const val FEEDS_COMMENTS = "/api/feeds/comments/{feed_id}"
private const val VIEW_FEEDS = "/api/feeds/view/{feed_id}"
private const val ADD_FAVORITE = "/api/feeds/add-favorite/{feed_id}"
private const val ADD_LIKE = "/api/feeds/add-like/{feed_id}"
private const val ADD_COMMENT = "/api/feeds/add-comment/{feed_id}"
private const val REQUESTS = "/api/requests-cs"
private const val REQUEST_DETAIL = "/api/request-detail"
private const val HOME = "/api/home"
private const val CANCEL_REQUEST = "/api/cancel-request"
private const val DOCTOR_LIST = "/api/doctor-list"
private const val BANNERS = "/api/banners"
private const val COUPONS = "/api/coupons"
private const val DOCTOR_DETAIL = "/api/doctor-detail"
private const val REVIEW_LIST = "/api/review-list"
private const val WALLET_HISTORY = "/api/wallet-history"
private const val CARD_LISTING = "/api/cards"
private const val WALLET = "/api/wallet"
private const val REQUEST_CHECK = "/api/request-check"
private const val CHAT_LISTING = "/api/chat-listing"
private const val CHAT_MESSAGES = "/api/chat-messages"
private const val NOTIFICATIONS = "/api/notifications"
private const val CATEGORIES = "/api/categories"
private const val CLASSES = "/api/classes"
private const val CLASS_DETAIL = "/api/class/detail"
private const val ENROLL_USER = "/api/enroll-user"
private const val CLASS_JOIN = "/api/class/join"
private const val ORDER_CREATE = "/api/order/create"
private const val HYPER_PAY_COMPLETE_DONE = "api/webhook/hyperpay"
private const val RAZOR_PAY_WEBHOOK = "/api/razor-pay-webhook"
private const val SERVICES = "/api/services"
private const val GET_FILTERS = "/api/get-filters"
private const val GET_SLOTS = "/api/get-slots"
private const val CALL_STATUS = "/api/call-status"
private const val PAGES = "/api/pages"
private const val PACK_SUB = "/api/pack-sub"
private const val PURCHASE_PACK = "/api/sub-pack"
private const val PACK_DETAIL = "/api/pack-detail"
private const val SUBSCRIPTIONS = "/api/subscriptions"
private const val SUBSCRIPTION_DETAIL = "/api/subscription-detail"
private const val SUBSCRIPTION_PACK = "/api/subscription-pack"
private const val ASK_QUESTIONS = "/api/ask-questions"
private const val ASK_QUESTIONS_DETAIL = "/api/ask-question-detail"
private const val WATER_LIMIT = "/api/water-limit"
private const val PROTEIN_LIMIT = "/api/protein-limit"
private const val DRINK_WATER = "/api/drink-water"
private const val DRINK_PROTEIN = "/api/drink-protein"
private const val ADD_FAMILY = "/api/add-family"
private const val SYMPTOM = "/api/symptoms"
private const val UPDATE_SYMPTOM = "/api/update-request-symptoms"
private const val EXTRA_PAYMENT = "/api/pay-extra-payment"
private const val CARE_PLANS = "/api/care-plans"
private const val TIERS = "/api/tiers"
private const val ADD_BANK = "/api/add-bank"
private const val BANK_ACCOUNTS = "/api/bank-accounts"
private const val GET_MEDICAL_HISTORY = "/api/get-medical-history"
private const val DIRECTIONS = "https://maps.googleapis.com/maps/api/directions/json"
private const val WORKING_HOURS = "/api/workingHours"
private const val SPEAKOUT_LIST = "/common/listSpeakouts"
/*V2 Api*/
private const val CREATE_REQUEST_V2 = "/api/v2/create-request"
private const val CONFIRM_REQUEST_V2 = "/api/v2/confirm-request"
private const val DOCTOR_LIST_V2 = "/api/v2/doctor-list"
private const val CANCEL_REQUEST_V2 = "/api/v2/cancel-request"
private const val CONTACT_LIST = "/api/contact-list"
private const val CONTACT_ADD = "/api/contact-add"
private const val CONTACT_DELETE = "/api/contact-delete"
private const val CONTACT_MESSAGE = "/api/contact-message"
}
/*POST APIS*/
@FormUrlEncoded
@POST(LOGIN)
fun login(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<UserData>>
@GET(INSPECTIONS_LIST)
fun inspectionsList(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<UserData>>
@POST(CREATE_INSPECTION)
fun createInspections(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<UserData>>
@GET(DAMAGES)
fun damagesList(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<UserData>>
@POST(DAMAGES)
fun createDamage(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<UserData>>
@DELETE("$DELETE_INSPECTIONS/{id}")
fun deleteInspections(@Path("id") id: String): Call<ApiResponse<UserData>>
@PUT("$UPDATE_INSPECTIONS/{id}")
fun updateInspection(@Path("id") id: String): Call<ApiResponse<UserData>>
@DELETE("$DAMAGES/{id}")
fun deleteDamage(@Path("id") id: String): Call<ApiResponse<UserData>>
@PUT("$DAMAGES/{id}")
fun updateDamage(@Path("id") id: String): Call<ApiResponse<UserData>>
/*
@FormUrlEncoded
@POST(APP_VERSION)
fun appVersion(@FieldMap hashMap: HashMap<String, String>): Call<ApiResponse<AppVersion>>
@FormUrlEncoded
@POST(UPDATE_NUMBER)
fun updateNumber(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<UserData>>
@FormUrlEncoded
@POST(VERIFY_OTP)
fun verifyOtp(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<UserData>>
@FormUrlEncoded
@POST(RESEND_OTP)
fun resendOtp(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<UserData>>
@FormUrlEncoded
@POST(REGISTER)
fun register(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<UserData>>
@FormUrlEncoded
@POST(FORGOT_PASSWORD)
fun forgotPassword(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<UserData>>
@FormUrlEncoded
@POST(CHANGE_PASSWORD)
fun changePassword(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<UserData>>
@FormUrlEncoded
@POST(PROFILE_UPDATE)
fun updateProfile(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<UserData>>
@FormUrlEncoded
@POST(COMPLETE_CHAT)
fun completeChat(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<CommonDataModel>>
@FormUrlEncoded
@POST(SEND_SMS)
fun sendSMS(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<UserData>>
@FormUrlEncoded
@POST(SEND_EMAIL_OTP)
fun sendEmailOtp(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<UserData>>
@FormUrlEncoded
@POST(EMAIL_VERIFY)
fun emailVerify(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<UserData>>
@POST(LOGOUT)
fun logout(): Call<ApiResponse<UserData>>
@FormUrlEncoded
@POST(UPDATE_FCM_ID)
fun updateFcmId(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<UserData>>
@POST(CREATE_REQUEST)
fun createRequest(@Body createRequest: CreateRequest): Call<ApiResponse<CommonDataModel>>
@POST(CREATE_REQUEST_V2)
fun createRequestV2(@Body createRequest: CreateRequest): Call<ApiResponse<CommonDataModel>>
@POST(CONFIRM_REQUEST)
fun confirmRequest(@Body createRequest: CreateRequest): Call<ApiResponse<CommonDataModel>>
@POST(CONFIRM_REQUEST_V2)
fun confirmRequestV2(@Body createRequest: CreateRequest): Call<ApiResponse<CommonDataModel>>
@FormUrlEncoded
@POST(ADD_CARD)
fun addCard(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<CommonDataModel>>
@FormUrlEncoded
@POST(UPDATE_CARD)
fun updateCard(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<CommonDataModel>>
@FormUrlEncoded
@POST(DELETE_CARD)
fun deleteCard(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<CommonDataModel>>
@FormUrlEncoded
@POST(ADD_MONEY)
fun addMoney(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<CommonDataModel>>
@Multipart
@POST(UPLOAD_IMAGE)
fun uploadFile(@PartMap map: HashMap<String, RequestBody>): Call<ApiResponse<CommonDataModel>>
@FormUrlEncoded
@POST(ADD_REVIEW)
fun addReview(@FieldMap hashMap: HashMap<String, String>): Call<ApiResponse<Any>>
@FormUrlEncoded
@POST(REQUEST_USER_APPROVE)
fun approveWorkingHour(@FieldMap hashMap: HashMap<String, String>): Call<ApiResponse<Any>>
@FormUrlEncoded
@POST(ENROLL_USER)
fun enrollUser(@FieldMap hashMap: HashMap<String, String>): Call<ApiResponse<CommonDataModel>>
@FormUrlEncoded
@POST(CLASS_JOIN)
fun joinClass(@FieldMap hashMap: HashMap<String, String>): Call<ApiResponse<CommonDataModel>>
@FormUrlEncoded
@POST(ORDER_CREATE)
fun orderCreate(@FieldMap hashMap: HashMap<String, String>): Call<ApiResponse<CommonDataModel>>
@FormUrlEncoded
@POST(HYPER_PAY_COMPLETE_DONE)
fun hyperPayCompleteTrans(@FieldMap hashMap: HashMap<String, String>): Call<ApiResponse<Any>>
@FormUrlEncoded
@POST(CANCEL_REQUEST_V2)
fun cancelRequest(@FieldMap hashMap: HashMap<String, String>): Call<ApiResponse<CommonDataModel>>
@FormUrlEncoded
@POST(CALL_STATUS)
fun callStatus(@FieldMap hashMap: HashMap<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(PACK_DETAIL)
fun packDetail(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(SUBSCRIPTION_DETAIL)
fun subscriptionDetail(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@FormUrlEncoded
@POST(PURCHASE_PACK)
fun purchasePack(@FieldMap hashMap: HashMap<String, String>): Call<ApiResponse<CommonDataModel>>
@FormUrlEncoded
@POST(SUBSCRIPTION_PACK)
fun subscriptionPack(@FieldMap hashMap: HashMap<String, String>): Call<ApiResponse<CommonDataModel>>
@FormUrlEncoded
@POST(ADD_FAVORITE)
fun addFavorite(@Path("feed_id") feed_id: String,
@FieldMap hashMap: HashMap<String, String>): Call<ApiResponse<CommonDataModel>>
@FormUrlEncoded
@POST(ADD_LIKE)
fun addLike(@Path("feed_id") feed_id: String,
@FieldMap hashMap: HashMap<String, String>): Call<ApiResponse<CommonDataModel>>
@FormUrlEncoded
@POST(ADD_COMMENT)
fun addComment(@Path("feed_id") feed_id: String,
@FieldMap hashMap: HashMap<String, String>): Call<ApiResponse<CommonDataModel>>
@FormUrlEncoded
@POST(RAZOR_PAY_WEBHOOK)
fun razorPayWebhook(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<CommonDataModel>>
@FormUrlEncoded
@POST(ASK_QUESTIONS)
fun askQuestion(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<CommonDataModel>>
@FormUrlEncoded
@POST(WATER_LIMIT)
fun setDailyLimit(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<WaterIntake>>
@FormUrlEncoded
@POST(PROTEIN_LIMIT)
fun setProteinDailyLimit(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<WaterIntake>>
@FormUrlEncoded
@POST(DRINK_WATER)
fun setWaterIntake(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<WaterIntake>>
@FormUrlEncoded
@POST(DRINK_PROTEIN)
fun setProteinIntake(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<WaterIntake>>
@FormUrlEncoded
@POST(ADD_FAMILY)
fun addFamily(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<CommonDataModel>>
@POST(UPDATE_SYMPTOM)
fun updateSymptom(@Body updateSymptom: UpdateSymptom): Call<ApiResponse<CommonDataModel>>
@POST(CARE_PLANS)
fun carePlans(@Body updateSymptom: UpdateSymptom): Call<ApiResponse<CommonDataModel>>
@FormUrlEncoded
@POST(ADD_BANK)
fun addBank(@FieldMap hashMap: HashMap<String, String>): Call<ApiResponse<CommonDataModel>>
*//*GET*//*
@GET(CLIENT_DETAILS)
fun clientDetails(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<AppVersion>>
@GET(COUNTRY_DATA)
fun countryData(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(PREFERENCES)
fun preferences(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(HOME)
fun home(): Call<ApiResponse<CommonDataModel>>
@GET(REQUESTS)
fun request(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(REQUEST_DETAIL)
fun requestDetail(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(DOCTOR_LIST)
fun doctorList(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(DOCTOR_LIST_V2)
fun doctorListV2(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(BANNERS)
fun banners(): Call<ApiResponse<CommonDataModel>>
@GET(DOCTOR_DETAIL)
fun doctorDetails(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(REVIEW_LIST)
fun reviewList(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(WALLET_HISTORY)
fun walletHistory(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(CARD_LISTING)
fun cardListing(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(WALLET)
fun wallet(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(CHAT_LISTING)
fun getChatListing(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(CHAT_MESSAGES)
fun getChatMessage(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(NOTIFICATIONS)
fun notifications(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(FEEDS)
fun getFeeds(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(FEEDS_COMMENTS)
fun getFeedsComment(@Path("feed_id") feed_id: String,
@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(VIEW_FEEDS)
fun viewFeeds(@Path("feed_id") feed_id: String): Call<ApiResponse<CommonDataModel>>
@GET(CATEGORIES)
fun categories(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(CLASSES)
fun classesList(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(CLASS_DETAIL)
fun classDetail(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<ClassData>>
@GET(GET_FILTERS)
fun getFilters(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(SERVICES)
fun services(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(GET_SLOTS)
fun getSlots(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(PAGES)
fun getPages(): Call<ApiResponse<CommonDataModel>>
@GET(COUPONS)
fun coupons(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(PACK_SUB)
fun packSub(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(SUBSCRIPTIONS)
fun subscriptions(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(DIRECTIONS)
fun directions(@QueryMap hashMap: Map<String, String>): Call<Direction>
@GET(ASK_QUESTIONS)
fun getQuestions(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(ASK_QUESTIONS_DETAIL)
fun getQuestionsDetails(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(WATER_LIMIT)
fun getWaterLimit(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<WaterIntake>>
@GET(PROTEIN_LIMIT)
fun getProteinIntake(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<WaterIntake>>
@GET(REQUEST_CHECK)
fun requestCheck(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(SYMPTOM)
fun symptom(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(TIERS)
fun carePlanTier(): Call<ApiResponse<CommonDataModel>>
@POST(EXTRA_PAYMENT)
fun payExtra(@Body extraPayment: Extra_payment): Call<ApiResponse<CommonDataModel>>
@GET(BANK_ACCOUNTS)
fun bankAccounts(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@GET(GET_MEDICAL_HISTORY)
fun getMedicalHistory(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
*//*PUT API*//*
@FormUrlEncoded
@PUT(WORKING_HOURS)
fun workingHours(@FieldMap hashMap: HashMap<String, String>): Call<ApiResponse<Any>>
@GET(CONTACT_LIST)
fun contactList(@QueryMap hashMap: Map<String, String>): Call<ApiResponse<CommonDataModel>>
@POST(CONTACT_ADD)
fun addContact(@Body contactList: ContactEmergency): Call<ApiResponse<CommonDataModel>>
@FormUrlEncoded
@POST(CONTACT_DELETE)
fun deletContact(@FieldMap hashMap: HashMap<String, Any>): Call<ApiResponse<CommonDataModel>>
@POST(CONTACT_MESSAGE)
fun sendMessage(): Call<ApiResponse<CommonDataModel>>*/
}

View file

@ -0,0 +1,29 @@
package com.consultantapp.data.models.requests
class AppFeatures {
var needUserDoctorScreen = false
var needWalkThrough = false
var needLanguageScreen = false
var needPackage = false
var needClasses = false
var needLocation = false
var subCategoryImageCenter = false
var homeConsultIcons = false
var needBlogs = false
var needArticles = false
var needHealthTools = false
var signUpAddition = false
var needInsuranceDocument = false
var needHomePatients = false
var needTestimonials = false
var needInviteCode = false
}

View file

@ -0,0 +1,6 @@
package com.consultantapp.data.models.requests
data class CarePlan (
var id: Int? = null,
var type: Int? = null
)

View file

@ -0,0 +1,7 @@
package com.consultantapp.data.models.requests
data class ConsultTypeModel (
var name: String? = null,
var image: Int? = null,
var type: String? = null
)

View file

@ -0,0 +1,23 @@
package com.consultantapp.data.models.requests
import java.io.Serializable
class CreateRequest : Serializable {
var consultant_id: String? = null
var schedule_type: String? = null
var service_id: String? = null
var request_id: String? = null
var category_id: String? = null
var date: String? = null
var time: String? = null
var end_date: String? = null
var end_time: String? = null
var coupon_code: String? = null
var service_address: String? = null
var lat: Double? = null
var long: Double? = null
var tier_id: Int? = null
var tier_options:ArrayList<CarePlan>?=null
}

View file

@ -0,0 +1,10 @@
package com.consultantapp.data.models.requests
class DatesAvailability {
var displayName: String? = null
var date: Long? = null
var isSelected = false
/*Water intake*/
var intakeAmount: Int? = null
}

View file

@ -0,0 +1,13 @@
package com.consultantapp.data.models.requests
import java.io.File
import java.io.Serializable
class DocImage : Serializable {
var imageFile: File? = null
var type: String? = null
var image: String? = null
var insuranceNumber: String? = null
var expiry: String? = null
}

View file

@ -0,0 +1,14 @@
package com.consultantapp.data.models.requests
import java.io.Serializable
data class SaveAddress (
var locationName: String? = null,
var houseNumber: String? = null,
var isDefault :Boolean = false,
var _id: String? = null,
var addressId: String? = null,
var lat: Double? = null,
var long: Double? = null
): Serializable

View file

@ -0,0 +1,11 @@
package com.consultantapp.data.models.requests
import java.io.Serializable
class SetFilter :Serializable{
var filter_id: Int? = null
var filter_option_ids: ArrayList<String>? = null
var preference_id: Int? = null
var option_ids: ArrayList<String>? = null
}

View file

@ -0,0 +1,16 @@
package com.consultantapp.data.models.requests
import java.io.Serializable
class UpdateSymptom : Serializable {
var request_id: String? = null
var image: ArrayList<DocImage>? = null
var images: ArrayList<DocImage>? = null
var option_ids: String? = null
var symptom_details: String? = null
var type: String? = null
}

View file

@ -0,0 +1,24 @@
package com.example.fieldagent.data.models.responses
data class UserData (
val status: Long? = null,
val success: Boolean? = null,
val message: String? = null,
val data: Data? = null
)
data class Data (
val id: Long? = null,
val name: String? = null,
val email: String? = null,
val phoneNumber: String? = null,
val designation: String? = null,
val createdAt: String? = null,
val updatedAt: String? = null,
val tokens: Tokens? = null
)
data class Tokens (
val accessToken: String? = null,
val refreshToken: String? = null
)

View file

@ -0,0 +1,67 @@
package com.example.fieldagent.data.network
import android.app.Activity
import androidx.appcompat.app.AlertDialog
import com.example.fieldagent.data.network.responseUtil.AppError
import com.example.fieldagent.R
object ApisRespHandler {
private var alertDialog: AlertDialog.Builder? = null
fun handleError(error: AppError?, activity: Activity,) {
error ?: return
when (error) {
is AppError.ApiError -> {
if (alertDialog == null)
errorMessage(activity, error.message)
}
is AppError.ApiUnauthorized -> {
}
is AppError.ApiAccountBlock -> {
}
is AppError.ApiAccountRuleChanged -> {
}
is AppError.ApiFailure -> {
if (alertDialog == null) {
if (error.message.contains("Failed to connect to",true) ||
error.message.contains("Unable to resolve host",true) ||
error.message.contains("No address associated with hostname",true))
errorMessage(activity, activity.getString(R.string.check_internet))
else
errorMessage(activity, error.message)
}
}
}
}
private fun errorMessage(activity: Activity, message: String?) {
try {
alertDialog = AlertDialog.Builder(activity)
alertDialog?.setCancelable(false)
alertDialog?.setTitle(activity.getString(R.string.alert))
alertDialog?.setMessage(message)
alertDialog?.setPositiveButton(activity.getString(R.string.ok)) { _, _ ->
alertDialog = null
}
alertDialog?.show()
} catch (ignored: Exception) {
}
}
}

View file

@ -0,0 +1,10 @@
package com.example.fieldagent.data.network
object Config {
var BASE_URL = "https://field-api.dmlabs.in/api/"
}

View file

@ -0,0 +1,6 @@
package com.example.fieldagent.data.network.responseUtil
data class ApiResponse<out T>(
val message: String? = null,
val data: T? = null
)

View file

@ -0,0 +1,54 @@
package com.example.fieldagent.data.network.responseUtil
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.asRequestBody
import org.json.JSONObject
import retrofit2.Response
import java.io.File
object ApiUtils {
private fun getErrorMessage(errorJson: String?): String {
if (errorJson.isNullOrBlank()) {
return ""
}
return try {
val errorJsonObject = JSONObject(errorJson)
errorJsonObject.getString("message")
} catch (exception: Exception) {
""
}
}
fun getError(statusCode: Int, errorJson: String?): AppError {
val message = getErrorMessage(errorJson)
return when (statusCode) {
401 -> {
AppError.ApiUnauthorized(message)
}
402 -> {
AppError.ApiAccountBlock(message)
}
403 -> {
AppError.ApiAccountRuleChanged(message)
}
else -> {
AppError.ApiError(statusCode, message)
}
}
}
fun failure(throwable: Throwable): AppError {
return AppError.ApiFailure(throwable.localizedMessage ?: "")
}
fun imageToRequestBody(imageFile: File): RequestBody =imageFile.asRequestBody("image/*".toMediaType())
fun imageToRequestBodyKey(parameterName: String, fileName: String): String =
"$parameterName\"; filename=\"$fileName"
}
fun <T> Response<T>.getAppError(): AppError {
return ApiUtils.getError(code(), errorBody()?.string())
}

View file

@ -0,0 +1,10 @@
package com.example.fieldagent.data.network.responseUtil
sealed class AppError {
data class ApiError(val statusCode: Int, val message: String) : AppError()
data class ApiUnauthorized(val message: String) : AppError()
data class ApiAccountBlock(val message: String) : AppError()
data class ApiAccountRuleChanged(val message: String) : AppError()
data class ApiFailure(val message: String) : AppError()
}

View file

@ -0,0 +1,24 @@
package com.example.fieldagent.data.network.responseUtil
import com.consultantapp.data.network.responseUtil.Status
/**
* A generic class that holds a value with its loading status.
* @param <T>
</T> */
data class Resource<out T>(val status: Status, val data: T?, val error: AppError?) {
companion object {
fun <T> success(data: T? = null): Resource<T> {
return Resource(Status.SUCCESS, data, null)
}
fun <T> error(error: AppError): Resource<T> {
return Resource(Status.ERROR, null, error)
}
fun <T> loading(): Resource<T> {
return Resource(Status.LOADING, null, null)
}
}
}

View file

@ -0,0 +1,14 @@
package com.consultantapp.data.network.responseUtil
/**
* Status of a resource that is provided to the UI.
*
*
* These are usually created by the Repository classes where they return
* `LiveData<Resource<T>>` to pass back the latest data to the UI with its fetch status.
*/
enum class Status {
SUCCESS,
ERROR,
LOADING
}

View file

@ -0,0 +1,42 @@
package com.example.fieldagent.di
import android.content.Context
import android.content.SharedPreferences
import android.preference.PreferenceManager
import com.google.gson.FieldNamingPolicy
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@InstallIn(SingletonComponent::class)
@Module
object AppModule {
@Provides
@Singleton
@JvmStatic
fun provideContext(@ApplicationContext app: Context): Context = app
@Provides
@Singleton
@JvmStatic
fun sharedPreferences(context: Context): SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
@Provides
@Singleton
@JvmStatic
fun provideGson(): Gson {
return GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.IDENTITY)
.setPrettyPrinting()
.setLenient()
.create()
}
}

View file

@ -0,0 +1,83 @@
package com.example.fieldagent.di
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.USER_DATA
import com.google.gson.Gson
import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import okhttp3.Interceptor
import okhttp3.logging.HttpLoggingInterceptor
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.converter.scalars.ScalarsConverterFactory
import java.util.*
import java.util.concurrent.TimeUnit
import javax.inject.Singleton
@InstallIn(SingletonComponent::class)
@Module
object NetworkModule {
@Provides
@Singleton
@JvmStatic
fun okHttpClient(prefsManager: PrefsManager): OkHttpClient {
return OkHttpClient.Builder()
.connectTimeout(100, TimeUnit.SECONDS)
.readTimeout(100, TimeUnit.SECONDS)
.writeTimeout(100, TimeUnit.SECONDS)
.addInterceptor(getHttpLoggingInterceptor())
.cache(null)
.addInterceptor(getNetworkInterceptor(prefsManager))
.build()
}
@Provides
@Singleton
@JvmStatic
fun retrofit(client: OkHttpClient, gson: Gson): Retrofit {
return Retrofit.Builder()
.baseUrl(Config.BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.addConverterFactory(ScalarsConverterFactory.create())
.addCallAdapterFactory(CoroutineCallAdapterFactory())
.build()
}
private fun getNetworkInterceptor(prefsManager: PrefsManager): Interceptor {
return Interceptor { chain ->
var request = chain.request()
val requestBuilder = request.newBuilder()
val accessToken = prefsManager.getObject(USER_DATA, UserData::class.java)?.data?.tokens?.accessToken
if (!accessToken.isNullOrEmpty())
requestBuilder.addHeader("authorization", "Bearer $accessToken")
request=requestBuilder.build()
chain.proceed(request)
}
}
private fun getHttpLoggingInterceptor(): HttpLoggingInterceptor {
val httpLoggingInterceptor = HttpLoggingInterceptor()
httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
return httpLoggingInterceptor
}
@Provides
@Singleton
@JvmStatic
fun webService(retrofit: Retrofit): WebService = retrofit.create(WebService::class.java)
}

View file

@ -0,0 +1,20 @@
package com.example.fieldagent.di
import android.content.Context
import android.content.res.Resources
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class ResourceProvider @Inject constructor(private val context: Context) {
fun getStringResource(stringId: Int): String {
// return LocaleHelper.onCreate(context).getString(stringId)
return "";
}
fun getResources(): Resources {
return context.resources
}
}

View file

@ -0,0 +1,58 @@
package com.example.fieldagent.di;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;
import java.util.concurrent.atomic.AtomicBoolean;
import timber.log.Timber;
/**
* A lifecycle-aware observable that sends only new updates after subscription, used for events USER_LIKE
* navigation and Snackbar messages.
* <p>
* This avoids a common problem with events: on configuration change (USER_LIKE rotation) an update
* can be emitted if the observer is active. This LiveData only calls the observable if there's an
* explicit call to setValue() or call().
* <p>
* Note that only one observer is going to be notified of changes.
*/
public class SingleLiveEvent<T> extends MutableLiveData<T> {
private final AtomicBoolean pending = new AtomicBoolean(false);
@MainThread
public void setObserver(@NonNull LifecycleOwner owner, @NonNull final Observer<T> observer) {
if (hasActiveObservers()) {
Timber.w("Multiple observers registered but only one will be notified of changes.");
}
// Observe the internal MutableLiveData
super.observe(owner, t -> {
if (pending.compareAndSet(true, false)) {
observer.onChanged(t);
}
});
}
@MainThread
public void setValue(@Nullable T t) {
pending.set(true);
super.setValue(t);
}
/**
* Used for cases where T is Void, to make calls cleaner.
*/
@MainThread
public void call() {
setValue(null);
}
}

View file

@ -0,0 +1,56 @@
package com.example.fieldagent.ui
import android.content.Intent
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.lifecycleScope
import com.example.fieldagent.R
import com.example.fieldagent.databinding.ActivityLoginBinding
import com.example.fieldagent.databinding.ActivitySplashBinding
import com.example.fieldagent.ui.homescreen.HomeActivity
import com.example.fieldagent.ui.login.LoginActivity
import com.example.fieldagent.utils.IS_LOGIN
import com.example.fieldagent.utils.PrefsManager
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.time.delay
import javax.inject.Inject
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@AndroidEntryPoint
class SplashActivity : AppCompatActivity() {
private lateinit var binding: ActivitySplashBinding
@Inject
lateinit var prefsManager: PrefsManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySplashBinding.inflate(layoutInflater)
setContentView(binding.root)
initialize()
}
private fun initialize(){
lifecycleScope.launch {
delay(1500)
if(prefsManager.getBoolean(IS_LOGIN,false)){
val intent = Intent(this@SplashActivity, HomeActivity::class.java)
startActivity(intent)
finish()
}else{
val intent = Intent(this@SplashActivity, LoginActivity::class.java)
startActivity(intent)
finish()
}
}
}
}

View file

@ -0,0 +1,71 @@
package com.example.fieldagent.ui.addsite
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import androidx.navigation.fragment.findNavController
import com.example.fieldagent.R
import com.example.fieldagent.databinding.FragmentAddSiteBinding
import com.example.fieldagent.databinding.FragmentHomeBinding
import com.example.fieldagent.ui.homescreen.adapter.HomeAdapter
class AddSiteFragment : Fragment() {
private var _binding: FragmentAddSiteBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentAddSiteBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val options = resources.getStringArray(R.array.availability).toList()
val adapter = ArrayAdapter(requireActivity(), R.layout.dropdown_item, options)
binding.autoCompleteBuilding.setAdapter(adapter)
binding.autoCompleteBuilding.setOnClickListener {
binding.autoCompleteBuilding.showDropDown()
}
val options2 = resources.getStringArray(R.array.condition).toList()
val adapter2 = ArrayAdapter(requireActivity(), R.layout.dropdown_item, options2)
binding.autoCompleteTextView.setAdapter(adapter2)
binding.autoCompleteTextView.setOnClickListener {
binding.autoCompleteTextView.showDropDown()
}
binding.ivLeft.setOnClickListener {
findNavController().popBackStack()
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -0,0 +1,73 @@
package com.example.fieldagent.ui.damagedetails
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.fieldagent.R
import com.example.fieldagent.databinding.FragmentDamageDetailsBinding
import com.example.fieldagent.databinding.FragmentDamageListBinding
import com.example.fieldagent.ui.damagedetails.adapter.DamageDetailsAdapter
import com.example.fieldagent.ui.homescreen.adapter.HomeAdapter
class DamageDetailsFragment : Fragment() {
private var _binding: FragmentDamageDetailsBinding? = null
private val binding get() = _binding!!
private lateinit var adapter: DamageDetailsAdapter
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentDamageDetailsBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
adapter = DamageDetailsAdapter()
binding.rvImage.layoutManager=
LinearLayoutManager(requireActivity(), LinearLayoutManager.HORIZONTAL, false)
binding.rvImage.adapter = adapter
val options = resources.getStringArray(R.array.mainItem).toList()
val adapter = ArrayAdapter(requireActivity(), R.layout.dropdown_item, options)
binding.autoCompleteMain.setAdapter(adapter)
binding.autoCompleteMain.setOnClickListener {
binding.autoCompleteMain.showDropDown()
}
val options2 = resources.getStringArray(R.array.SubItem).toList()
val adapter2 = ArrayAdapter(requireActivity(), R.layout.dropdown_item, options2)
binding.autoCompleteSub.setAdapter(adapter2)
binding.autoCompleteSub.setOnClickListener {
binding.autoCompleteSub.showDropDown()
}
binding.ivLeft.setOnClickListener {
findNavController().popBackStack()
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -0,0 +1,34 @@
package com.example.fieldagent.ui.damagedetails.adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.fieldagent.R
class DamageDetailsAdapter() : RecyclerView.Adapter<DamageDetailsAdapter.DamageViewHolder>() {
class DamageViewHolder(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)*/
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DamageViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.damage_image_adapter, parent, false)
return DamageViewHolder(view)
}
override fun onBindViewHolder(holder: DamageViewHolder, position: Int) {
/* holder.nameText.text =" user.name"
holder.locationText.text =" user.address"
holder.timeText.text = "user.time"*/
}
override fun getItemCount(): Int = 4
}

View file

@ -0,0 +1,51 @@
package com.example.fieldagent.ui.damagelist
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.fieldagent.R
import com.example.fieldagent.databinding.FragmentAddSiteBinding
import com.example.fieldagent.databinding.FragmentDamageListBinding
import com.example.fieldagent.ui.damagedetails.adapter.DamageDetailsAdapter
import com.example.fieldagent.ui.damagelist.adapter.DamageListAdapter
class DamageListFragment : Fragment() {
private var _binding: FragmentDamageListBinding? = null
private val binding get() = _binding!!
private lateinit var adapter: DamageListAdapter
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentDamageListBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
adapter = DamageListAdapter()
binding.rvDamageList.adapter = adapter
binding.llBtn.setOnClickListener{
findNavController().navigate(R.id.damageDeatilsFragment)
}
binding.ivLeft.setOnClickListener {
findNavController().popBackStack()
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -0,0 +1,39 @@
package com.example.fieldagent.ui.damagelist.adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.fieldagent.R
import com.example.fieldagent.ui.damagedetails.adapter.DamageDetailsAdapter
class DamageListAdapter() : RecyclerView.Adapter<DamageListAdapter.DamageHolder>() {
class DamageHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val recyclerView: RecyclerView = itemView.findViewById(R.id.rvImage)
//val locationText: TextView = itemView.findViewById(R.id.txtLocation)
// val timeText: TextView = itemView.findViewById(R.id.txtTime)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DamageHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.damage_view_adapter, parent, false)
return DamageHolder(view)
}
override fun onBindViewHolder(holder: DamageHolder, position: Int) {
val adapter = ShowImageAdapter()
holder.recyclerView.layoutManager=
LinearLayoutManager(holder.itemView.context, LinearLayoutManager.HORIZONTAL, false)
holder.recyclerView.adapter = adapter
/* holder.nameText.text =" user.name"
holder.locationText.text =" user.address"
holder.timeText.text = "user.time"*/
}
override fun getItemCount(): Int = 4
}

View file

@ -0,0 +1,33 @@
package com.example.fieldagent.ui.damagelist.adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.fieldagent.R
class ShowImageAdapter() : RecyclerView.Adapter<ShowImageAdapter.ShowImageHolder>() {
class ShowImageHolder(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)*/
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ShowImageHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.fill_image_adapter, parent, false)
return ShowImageHolder(view)
}
override fun onBindViewHolder(holder: ShowImageHolder, position: Int) {
/* holder.nameText.text =" user.name"
holder.locationText.text =" user.address"
holder.timeText.text = "user.time"*/
}
override fun getItemCount(): Int = 4
}

View file

@ -0,0 +1,21 @@
package com.example.fieldagent.ui.homescreen
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
import com.example.fieldagent.R
import com.example.fieldagent.databinding.ActivityHomeBinding
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class HomeActivity : AppCompatActivity() {
private lateinit var binding: ActivityHomeBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityHomeBinding.inflate(layoutInflater)
setContentView(binding.root)
}
}

View file

@ -0,0 +1,285 @@
package com.example.fieldagent.ui.homescreen
import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.PopupMenu
import android.widget.PopupWindow
import android.widget.TextView
import androidx.activity.viewModels
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
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.fragment.app.viewModels
import com.consultantapp.data.network.responseUtil.Status
import com.example.fieldagent.data.network.ApisRespHandler
import com.example.fieldagent.ui.login.LoginActivity
import com.example.fieldagent.ui.login.LoginViewModel
import com.example.fieldagent.utils.IS_LOGIN
import com.example.fieldagent.utils.PrefsManager
import com.example.fieldagent.utils.USER_DATA
import com.example.fieldagent.utils.dialogs.ProgressDialog
import dagger.hilt.android.AndroidEntryPoint
import java.util.HashMap
import javax.inject.Inject
import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView
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.PER_PAGE
import com.example.fieldagent.utils.PER_PAGE_LOAD
import com.example.fieldagent.utils.gone
import com.example.fieldagent.utils.hideShowView
import com.example.fieldagent.utils.isConnectedToInternet
import com.example.fieldagent.utils.visible
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@AndroidEntryPoint
class HomeFragment : Fragment() {
private var _binding: FragmentHomeBinding? = null
private val binding get() = _binding!!
private lateinit var adapter: HomeAdapter
@Inject
lateinit var prefsManager: PrefsManager
private val viewModel: HomeViewModel by viewModels()
private lateinit var progressDialog: ProgressDialog
private var items = ArrayList<UserData>()
private var isLastPage = false
private var isFirstPage = true
private var isLoadingMoreItems = false
private var searchJob: Job? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initialize()
bindObservers()
setAdapter()
listener()
}
private fun initialize(){
prefsManager.save(IS_LOGIN,true)
val hashMap = HashMap<String, String>()
hashMap["limit"] = "10"
hashMap["Page"] = "1"
viewModel.getInspectionList(hashMap);
}
private fun setAdapter(){
binding.rvList.layoutManager = LinearLayoutManager(requireActivity())
adapter = HomeAdapter(this,items)
binding.rvList.adapter = adapter
binding.rvList.itemAnimator = null
}
private fun listener(){
binding.llBtn.setOnClickListener {
findNavController().navigate(R.id.addSiteFragment)
}
binding.llLogoutBtn.setOnClickListener {
val intent = Intent(requireActivity(), LoginActivity::class.java)
startActivity(intent)
requireActivity().finish()
}
binding.ivFilter.setOnClickListener {
val inflater = LayoutInflater.from(binding.ivFilter.context)
val parent = binding.root as ViewGroup
val popupView = PopLayoutBinding.inflate(inflater,parent,false)
val popupWindow = PopupWindow(
popupView.root,
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
true // focusable
)
popupView.txtCompleted.setOnClickListener {
refreshPagination()
hitApi(false)
}
popupView.txtInProgress.setOnClickListener {
refreshPagination()
hitApi(false)
}
popupWindow.setBackgroundDrawable(Color.TRANSPARENT.toDrawable())
popupWindow.isOutsideTouchable = true
popupWindow.elevation = 40f
popupWindow.showAsDropDown(binding.ivFilter)
}
binding.swipeRefresh.setOnRefreshListener {
hitApi(true)
}
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()
if (!isLoadingMoreItems && !isLastPage && lastVisibleItemPosition >= totalItemCount) {
isLoadingMoreItems = true
hitApi(false)
}
}
})
binding.etSearch.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
// Debounce: cancel any previous search job
searchJob?.cancel()
searchJob = lifecycleScope.launch {
delay(300) // wait for user to stop typing (300ms)
val query = s.toString()
if (query.isNotBlank()) {
refreshPagination()
hitApi(false)
}
}
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
})
}
private fun refreshPagination(){
isLastPage = false
isFirstPage = true
isLoadingMoreItems = false
}
private fun hitApi(firstHit: Boolean) {
if (isConnectedToInternet(requireContext(), true)) {
if (firstHit) {
isFirstPage = true
isLastPage = false
}
val hashMap = HashMap<String, String>()
if (!isFirstPage && items.isNotEmpty())
// hashMap[AFTER] = items[items.size - 1].id ?: ""
hashMap[PER_PAGE] = PER_PAGE_LOAD.toString()
viewModel.getInspectionList(hashMap)
} else
binding.swipeRefresh.isRefreshing = false
}
private fun bindObservers() {
viewModel.inspections.observe(requireActivity(), Observer {
it ?: return@Observer
when (it.status) {
Status.SUCCESS -> {
binding.clLoader.root.gone()
binding.swipeRefresh.isRefreshing = false
isLoadingMoreItems = false
// val tempList = it.data?.notifications ?: emptyList()
val tempList=ArrayList<UserData>()
if (isFirstPage) {
isFirstPage = false
items.clear()
items.addAll(tempList)
adapter.notifyDataSetChanged()
} else {
val oldSize = items.size
items.addAll(tempList)
adapter.notifyItemRangeInserted(oldSize, items.size)
}
isLastPage = tempList.size < PER_PAGE_LOAD
adapter.setAllItemsLoaded(isLastPage)
binding.clNoData.rootView.hideShowView(items.isEmpty())
}
Status.ERROR -> {
isLoadingMoreItems = false
adapter.setAllItemsLoaded(true)
binding.swipeRefresh.isRefreshing = false
binding.clLoader.root.gone()
ApisRespHandler.handleError(it.error, requireActivity())
}
Status.LOADING -> {
if (!isLoadingMoreItems && !binding.swipeRefresh.isRefreshing)
binding.clLoader.root.visible()
}
}
})
}
fun clickItem(pos: Int) {
val item = items[pos]
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -0,0 +1,49 @@
package com.example.fieldagent.ui.homescreen
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 retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import javax.inject.Inject
@HiltViewModel
class HomeViewModel @Inject constructor(private val webService: WebService) : ViewModel() {
val inspections by lazy { SingleLiveEvent<Resource<UserData>>() }
fun getInspectionList(hashMap: HashMap<String, String>) {
inspections.value = Resource.loading()
webService.inspectionsList(hashMap)
.enqueue(object : Callback<ApiResponse<UserData>> {
override fun onResponse(call: Call<ApiResponse<UserData>>,
response: Response<ApiResponse<UserData>>
) {
if (response.isSuccessful) {
inspections.value = Resource.success(response.body()?.data)
} else {
inspections.value = Resource.error(
ApiUtils.getError(response.code(),
response.errorBody()?.string()))
}
}
override fun onFailure(call: Call<ApiResponse<UserData>>, throwable: Throwable) {
inspections.value = Resource.error(ApiUtils.failure(throwable))
}
})
}
}

View file

@ -0,0 +1,101 @@
package com.example.fieldagent.ui.homescreen.adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.fragment.app.FragmentActivity
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.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.LoadingStatus.ITEM
import com.example.fieldagent.utils.LoadingStatus.LOADING
class HomeAdapter(private val fragment: HomeFragment,private val items: ArrayList<UserData>) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var allItemsLoaded = true
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder.itemViewType != LOADING)
(holder as ViewHolder).bind(items[position])
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == ITEM) {
ViewHolder(HomeAdapterBinding.inflate(LayoutInflater.from(parent.context), parent, false))
} else {
ViewHolderLoader(ItemPagingLoaderBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
}
override fun getItemCount(): Int = if (allItemsLoaded) items.size else items.size + 1
override fun getItemViewType(position: Int) = if (position >= items.size) LOADING else ITEM
inner class ViewHolder(val binding: HomeAdapterBinding) :
RecyclerView.ViewHolder(binding.root) {
init {
binding.clMain.setOnClickListener {
fragment.clickItem(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)*/
}
}
inner class ViewHolderLoader(val binding: ItemPagingLoaderBinding) :
RecyclerView.ViewHolder(binding.root)
fun setAllItemsLoaded(allLoaded: Boolean) {
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

@ -0,0 +1,101 @@
package com.example.fieldagent.ui.login
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.util.Log
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.network.ApisRespHandler
import com.example.fieldagent.databinding.ActivityLoginBinding
import com.example.fieldagent.ui.homescreen.HomeActivity
import com.example.fieldagent.utils.PrefsManager
import com.example.fieldagent.utils.USER_DATA
import com.example.fieldagent.utils.dialogs.ProgressDialog
import com.example.fieldagent.utils.isConnectedToInternet
import com.example.fieldagent.utils.showSnackBar
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@AndroidEntryPoint
class LoginActivity : AppCompatActivity() {
private lateinit var binding: ActivityLoginBinding
@Inject
lateinit var prefsManager: PrefsManager
private val viewModel: LoginViewModel by viewModels()
private lateinit var progressDialog: ProgressDialog
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityLoginBinding.inflate(layoutInflater)
setContentView(binding.root)
initialise()
listeners()
bindObservers()
}
private fun initialise() {
progressDialog = ProgressDialog(this)
}
private fun listeners(){
binding.btnSigIn.setOnClickListener {
when{
binding.etEmail.text.toString().isEmpty() -> {
binding.etEmail.showSnackBar(getString(R.string.enter_email))
}
!Patterns.EMAIL_ADDRESS.matcher(binding.etEmail.text.toString()).matches() -> {
binding.etEmail.showSnackBar(getString(R.string.enter_correct_email))
}
binding.etPassword.text.toString().length < 6 -> {
binding.etPassword.showSnackBar(getString(R.string.enter_password))
}
isConnectedToInternet(this, true) -> {
val hashMap = HashMap<String, Any>()
hashMap["email"] = binding.etEmail.text.toString()
hashMap["password"] = binding.etPassword.text.toString()
viewModel.login(hashMap)
}
}
}
}
private fun bindObservers() {
viewModel.login.observe(this, Observer {
it ?: return@Observer
when (it.status) {
Status.SUCCESS -> {
progressDialog.setLoading(false)
prefsManager.save(USER_DATA, it.data)
val intent = Intent(this, HomeActivity::class.java)
startActivity(intent)
finish()
}
Status.ERROR -> {
progressDialog.setLoading(false)
ApisRespHandler.handleError(it.error,this)
}
Status.LOADING -> {
progressDialog.setLoading(true)
}
}
})
}
}

View file

@ -0,0 +1,50 @@
package com.example.fieldagent.ui.login
import android.content.Intent
import androidx.core.content.ContextCompat.startActivity
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 com.example.fieldagent.ui.homescreen.HomeActivity
import dagger.hilt.android.lifecycle.HiltViewModel
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import javax.inject.Inject
@HiltViewModel
class LoginViewModel @Inject constructor(private val webService: WebService) : ViewModel() {
val login by lazy { SingleLiveEvent<Resource<UserData>>() }
fun login(hashMap: HashMap<String, Any>) {
login.value = Resource.loading()
webService.login(hashMap)
.enqueue(object : Callback<ApiResponse<UserData>> {
override fun onResponse(call: Call<ApiResponse<UserData>>,
response: Response<ApiResponse<UserData>>
) {
if (response.isSuccessful) {
login.value = Resource.success(response.body()?.data)
} else {
login.value = Resource.error(
ApiUtils.getError(response.code(),
response.errorBody()?.string()))
}
}
override fun onFailure(call: Call<ApiResponse<UserData>>, throwable: Throwable) {
login.value = Resource.error(ApiUtils.failure(throwable))
}
})
}
}

View file

@ -0,0 +1,18 @@
package com.example.fieldagent.utils
const val USER_DATA = "userData"
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
object LoadingStatus {
const val ITEM = 0
const val LOADING = 1
}

View file

@ -0,0 +1,48 @@
package com.example.fieldagent.utils
import android.Manifest
import android.content.Context
import android.content.Intent
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import android.util.Log
import android.widget.Toast
import androidx.annotation.RequiresPermission
import com.example.fieldagent.R
/* fun showRetrofitErrorToast() {
Toast.makeText(context, context.getString(R.string.might_problem), Toast.LENGTH_LONG).show()
}*/
fun isConnectedToInternet(context: Context, showAlert: Boolean): Boolean {
val isConnected = isConnectedToInternet(context)
if (!isConnected)
{
Toast.makeText(context,context.getString(R.string.check_internet),Toast.LENGTH_SHORT).show()
return false
}else{
return true
}
}
private fun isConnectedToInternet(context: Context?): Boolean {
val connectivityManager = context?.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val activeNetwork = connectivityManager.activeNetwork ?: return false
val networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork)
?: return false
return when {
networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
//for other device how are able to connect with Ethernet
networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
//for check internet over Bluetooth
networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> true
else -> false
}
}

View file

@ -0,0 +1,51 @@
package com.example.fieldagent.utils
import android.content.Context
import android.view.View
import android.widget.TextView
import android.widget.Toast
import androidx.core.content.ContextCompat
import com.example.fieldagent.R
import com.google.android.material.snackbar.Snackbar
fun View.gone() {
visibility = View.GONE
}
fun View.visible() {
visibility = View.VISIBLE
}
fun View.invisible() {
visibility = View.INVISIBLE
}
fun View.hideShowView(listIsEmpty: Boolean) {
visibility = if (listIsEmpty) View.VISIBLE
else View.GONE
}
fun View.showSnackBar(msg: String) {
try {
val snackBar = Snackbar.make(this, msg, Snackbar.LENGTH_LONG)
val snackBarView = snackBar.view
val textView =
snackBarView.findViewById<View>(com.google.android.material.R.id.snackbar_text) as TextView
textView.maxLines = 3
snackBar.setAction(R.string.ok) { snackBar.dismiss() }
snackBarView.setBackgroundColor(ContextCompat.getColor(context, R.color.main_color))
snackBar.setActionTextColor(ContextCompat.getColor(context, R.color.white))
snackBar.show()
} catch (e: Exception) {
e.printStackTrace()
}
}
fun Context.longToast(text: CharSequence) {
Toast.makeText(this, text, Toast.LENGTH_LONG).show()
}

View file

@ -0,0 +1,72 @@
package com.example.fieldagent.utils
import android.content.SharedPreferences
import androidx.annotation.StringDef
import com.google.gson.Gson
import java.util.concurrent.atomic.AtomicBoolean
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class PrefsManager @Inject constructor(private val preferences: SharedPreferences, private val gson: Gson) {
private val sharedPrefName = "ArabLife"
companion object {
annotation class PrefKey
private lateinit var instance: PrefsManager
fun get(): PrefsManager = instance }
fun save(@PrefKey key: String, value: String) {
preferences.edit().putString(key, value).apply()
}
fun save(@PrefKey key: String, value: Int) {
preferences.edit().putInt(key, value).apply()
}
fun save(@PrefKey key: String, value: Boolean) {
preferences.edit().putBoolean(key, value).apply()
}
fun save(@PrefKey key: String, `object`: Any?) {
if (`object` == null) {
throw IllegalArgumentException("object is null")
}
// Convert the provided object to JSON string
save(key, gson.toJson(`object`))
}
fun <T> getObject(@PrefKey key: String, objectClass: Class<T>): T? {
val jsonString = preferences.getString(key, null)
return if (jsonString == null) {
null
} else {
try {
gson.fromJson(jsonString, objectClass)
} catch (e: Exception) {
throw IllegalArgumentException("Object stored with key $key is instance of other class")
}
}
}
fun getString(@PrefKey key: String, defValue: String): String =
preferences.getString(key, defValue) ?:""
fun getInt(@PrefKey key: String, defValue: Int): Int = preferences.getInt(key, defValue)
fun getFloat(@PrefKey key: String, defValue: Float): Float = preferences.getFloat(key, defValue)
fun getBoolean(@PrefKey key: String, defValue: Boolean): Boolean =
preferences.getBoolean(key, defValue)
fun removeAll() {
preferences.edit().clear().apply()
}
fun remove(key: String) {
preferences.edit().remove(key).apply()
}
}

View file

@ -0,0 +1,38 @@
package com.example.fieldagent.utils.dialogs
import android.app.Activity
import android.app.Dialog
import android.view.View
import android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND
import com.example.fieldagent.R
class ProgressDialog() {
private lateinit var dialog: Dialog
constructor(context: Activity) : this() {
val dialogView = View.inflate(context, R.layout.dialog_progress, null)
dialog = Dialog(context, R.style.CustomDialog)
dialog.window?.clearFlags(FLAG_DIM_BEHIND)
dialog.setContentView(dialogView)
dialog.setCancelable(false)
}
private fun show() {
if (!dialog.isShowing)
dialog.show()
}
private fun dismiss() {
if (dialog.isShowing)
dialog.dismiss()
}
fun setLoading(isLoading: Boolean) {
if (isLoading)
show()
else
dismiss()
}
}

View file

@ -0,0 +1,20 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:pathData="M5,10H15"
android:strokeLineJoin="round"
android:strokeWidth="1.25"
android:fillColor="#00000000"
android:strokeColor="#FDFDFD"
android:strokeLineCap="round"/>
<path
android:pathData="M10,15V5"
android:strokeLineJoin="round"
android:strokeWidth="1.25"
android:fillColor="#00000000"
android:strokeColor="#FDFDFD"
android:strokeLineCap="round"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

View file

@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12,19L5,12M5,12L12,5M5,12H19"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#000000"
android:strokeLineCap="round"/>
</vector>

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white" />
<corners android:bottomLeftRadius="@dimen/dp_8"
android:bottomRightRadius="@dimen/dp_8"
/>
<stroke
android:width="0.05dp"
android:color="@color/outline_grey_color" />
</shape>

View file

@ -0,0 +1,20 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:strokeWidth="1"
android:pathData="M14.667,8C14.667,11.68 11.68,14.667 8,14.667C4.32,14.667 1.334,11.68 1.334,8C1.334,4.32 4.32,1.334 8,1.334C11.68,1.334 14.667,4.32 14.667,8Z"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#285747"
android:strokeLineCap="round"/>
<path
android:strokeWidth="1"
android:pathData="M10.473,10.12L8.407,8.886C8.047,8.673 7.753,8.16 7.753,7.74V5.006"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#285747"
android:strokeLineCap="round"/>
</vector>

View file

@ -0,0 +1,27 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:strokeWidth="1"
android:pathData="M8,14.667C11.667,14.667 14.667,11.667 14.667,8C14.667,4.333 11.667,1.333 8,1.333C4.333,1.333 1.334,4.333 1.334,8C1.334,11.667 4.333,14.667 8,14.667Z"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#292D32"
android:strokeLineCap="round"/>
<path
android:strokeWidth="1"
android:pathData="M6.113,9.887L9.887,6.113"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#292D32"
android:strokeLineCap="round"/>
<path
android:strokeWidth="1"
android:pathData="M9.887,9.887L6.113,6.113"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#292D32"
android:strokeLineCap="round"/>
</vector>

View file

@ -0,0 +1,27 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="18dp"
android:height="18dp"
android:viewportWidth="18"
android:viewportHeight="18">
<path
android:pathData="M14.8,6.36C12.62,6.14 10.42,6.03 8.23,6.03C6.93,6.03 5.63,6.1 4.34,6.23L3,6.36"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#292D32"
android:strokeLineCap="round"/>
<path
android:pathData="M6.61,5.7L6.75,4.84C6.85,4.22 6.93,3.75 8.04,3.75H9.76C10.87,3.75 10.95,4.24 11.05,4.84L11.19,5.69"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#292D32"
android:strokeLineCap="round"/>
<path
android:pathData="M13.39,6.44L12.96,13.04C12.89,14.07 12.83,14.87 11,14.87H6.79C4.96,14.87 4.9,14.07 4.83,13.04L4.4,6.44"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#292D32"
android:strokeLineCap="round"/>
</vector>

View file

@ -0,0 +1,27 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:strokeWidth="1"
android:pathData="M5.781,9.553C5.781,10.413 6.441,11.106 7.261,11.106H8.935C9.648,11.106 10.228,10.5 10.228,9.753C10.228,8.94 9.875,8.653 9.348,8.466L6.661,7.533C6.135,7.346 5.781,7.06 5.781,6.246C5.781,5.5 6.361,4.893 7.075,4.893H8.748C9.568,4.893 10.228,5.586 10.228,6.446"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#285747"
android:strokeLineCap="round"/>
<path
android:strokeWidth="1"
android:pathData="M8,4V12"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#285747"
android:strokeLineCap="round"/>
<path
android:strokeWidth="1"
android:pathData="M8,14.667C11.682,14.667 14.667,11.682 14.667,8C14.667,4.318 11.682,1.334 8,1.334C4.318,1.334 1.334,4.318 1.334,8C1.334,11.682 4.318,14.667 8,14.667Z"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#285747"
android:strokeLineCap="round"/>
</vector>

View file

@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M6,9L12,15L18,9"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#333333"
android:strokeLineCap="round"/>
</vector>

View file

@ -0,0 +1,27 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:pathData="M11.05,3L4.208,10.242C3.95,10.517 3.7,11.058 3.65,11.433L3.342,14.133C3.233,15.108 3.933,15.775 4.9,15.608L7.583,15.15C7.958,15.083 8.483,14.808 8.742,14.525L15.583,7.283C16.767,6.033 17.3,4.608 15.458,2.867C13.625,1.142 12.233,1.75 11.05,3Z"
android:strokeLineJoin="round"
android:strokeWidth="1.25"
android:fillColor="#00000000"
android:strokeColor="#292D32"
android:strokeLineCap="round"/>
<path
android:pathData="M9.908,4.208C10.267,6.509 12.133,8.267 14.45,8.5"
android:strokeLineJoin="round"
android:strokeWidth="1.25"
android:fillColor="#00000000"
android:strokeColor="#292D32"
android:strokeLineCap="round"/>
<path
android:pathData="M2.5,18.333H17.5"
android:strokeLineJoin="round"
android:strokeWidth="1.25"
android:fillColor="#00000000"
android:strokeColor="#292D32"
android:strokeLineCap="round"/>
</vector>

View file

@ -0,0 +1,48 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="21dp"
android:viewportWidth="20"
android:viewportHeight="21">
<path
android:pathData="M5.417,2.167V7.167"
android:strokeLineJoin="round"
android:strokeWidth="1.25"
android:fillColor="#00000000"
android:strokeColor="#285747"
android:strokeLineCap="round"/>
<path
android:pathData="M5.417,15.5V18.833"
android:strokeLineJoin="round"
android:strokeWidth="1.25"
android:fillColor="#00000000"
android:strokeColor="#285747"
android:strokeLineCap="round"/>
<path
android:pathData="M8.333,12.167C8.333,10.556 7.028,9.25 5.417,9.25C3.806,9.25 2.5,10.556 2.5,12.167C2.5,13.778 3.806,15.083 5.417,15.083C7.028,15.083 8.333,13.778 8.333,12.167Z"
android:strokeLineJoin="round"
android:strokeWidth="1.25"
android:fillColor="#00000000"
android:strokeColor="#285747"
android:strokeLineCap="round"/>
<path
android:pathData="M14.583,2.167V5.5"
android:strokeLineJoin="round"
android:strokeWidth="1.25"
android:fillColor="#00000000"
android:strokeColor="#285747"
android:strokeLineCap="round"/>
<path
android:pathData="M14.583,13.833V18.833"
android:strokeLineJoin="round"
android:strokeWidth="1.25"
android:fillColor="#00000000"
android:strokeColor="#285747"
android:strokeLineCap="round"/>
<path
android:pathData="M17.5,8.833C17.5,7.222 16.194,5.917 14.583,5.917C12.972,5.917 11.667,7.222 11.667,8.833C11.667,10.444 12.972,11.75 14.583,11.75C16.194,11.75 17.5,10.444 17.5,8.833Z"
android:strokeLineJoin="round"
android:strokeWidth="1.25"
android:fillColor="#00000000"
android:strokeColor="#285747"
android:strokeLineCap="round"/>
</vector>

View file

@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="45dp"
android:height="44dp"
android:viewportWidth="45"
android:viewportHeight="44">
<path
android:pathData="M22.5,0L22.5,0A22,22 0,0 1,44.5 22L44.5,22A22,22 0,0 1,22.5 44L22.5,44A22,22 0,0 1,0.5 22L0.5,22A22,22 0,0 1,22.5 0z"
android:fillColor="#F5F5F5"/>
<path
android:pathData="M20,30.333H25C29.167,30.333 30.833,28.667 30.833,24.5V19.5C30.833,15.333 29.167,13.667 25,13.667H20C15.833,13.667 14.167,15.333 14.167,19.5V24.5C14.167,28.667 15.833,30.333 20,30.333Z"
android:strokeLineJoin="round"
android:strokeWidth="1.25"
android:fillColor="#00000000"
android:strokeColor="#292D32"
android:strokeLineCap="round"/>
<path
android:pathData="M20,20.333C20.921,20.333 21.667,19.587 21.667,18.667C21.667,17.746 20.921,17 20,17C19.08,17 18.333,17.746 18.333,18.667C18.333,19.587 19.08,20.333 20,20.333Z"
android:strokeLineJoin="round"
android:strokeWidth="1.25"
android:fillColor="#00000000"
android:strokeColor="#292D32"
android:strokeLineCap="round"/>
<path
android:pathData="M14.725,27.792L18.833,25.034C19.492,24.592 20.442,24.642 21.033,25.15L21.308,25.392C21.958,25.95 23.008,25.95 23.658,25.392L27.125,22.417C27.775,21.858 28.825,21.858 29.475,22.417L30.833,23.583"
android:strokeLineJoin="round"
android:strokeWidth="1.25"
android:fillColor="#00000000"
android:strokeColor="#292D32"
android:strokeLineCap="round"/>
</vector>

View file

@ -0,0 +1,48 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12,19.5C16.142,19.5 19.5,16.142 19.5,12C19.5,7.858 16.142,4.5 12,4.5C7.858,4.5 4.5,7.858 4.5,12C4.5,16.142 7.858,19.5 12,19.5Z"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#285747"
android:strokeLineCap="round"/>
<path
android:pathData="M12,15C13.657,15 15,13.657 15,12C15,10.343 13.657,9 12,9C10.343,9 9,10.343 9,12C9,13.657 10.343,15 12,15Z"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#285747"
android:strokeLineCap="round"/>
<path
android:pathData="M12,4V2"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#285747"
android:strokeLineCap="round"/>
<path
android:pathData="M4,12H2"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#285747"
android:strokeLineCap="round"/>
<path
android:pathData="M12,20V22"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#285747"
android:strokeLineCap="round"/>
<path
android:pathData="M20,12H22"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#285747"
android:strokeLineCap="round"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

View file

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View file

@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -0,0 +1,13 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/grey_color" />
<stroke
android:width="1dp"
android:color="@color/outline_grey_color"
android:dashWidth="10dp"
android:dashGap="5dp" />
<corners android:radius="4dp" />
</shape>

View file

@ -0,0 +1,13 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@android:color/transparent" />
<stroke
android:width="1dp"
android:color="@color/outline_grey_color"
android:dashWidth="10dp"
android:dashGap="5dp" />
<corners android:radius="4dp" />
</shape>

View file

@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:strokeWidth="1"
android:pathData="M8,8.953C9.149,8.953 10.08,8.022 10.08,6.873C10.08,5.725 9.149,4.793 8,4.793C6.851,4.793 5.92,5.725 5.92,6.873C5.92,8.022 6.851,8.953 8,8.953Z"
android:fillColor="#00000000"
android:strokeColor="#285747"/>
<path
android:strokeWidth="1"
android:pathData="M2.413,5.66C3.727,-0.113 12.28,-0.107 13.587,5.667C14.353,9.054 12.247,11.92 10.4,13.693C9.06,14.987 6.94,14.987 5.593,13.693C3.753,11.92 1.647,9.047 2.413,5.66Z"
android:fillColor="#00000000"
android:strokeColor="#285747"/>
</vector>

View file

@ -0,0 +1,27 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:pathData="M12.583,13.7C12.325,16.7 10.783,17.925 7.409,17.925H7.3C3.575,17.925 2.083,16.433 2.083,12.708L2.083,7.275C2.083,3.55 3.575,2.058 7.3,2.058H7.409C10.759,2.058 12.3,3.266 12.575,6.216"
android:strokeLineJoin="round"
android:strokeWidth="1.25"
android:fillColor="#00000000"
android:strokeColor="#EE5445"
android:strokeLineCap="round"/>
<path
android:pathData="M7.5,10L16.983,10"
android:strokeLineJoin="round"
android:strokeWidth="1.25"
android:fillColor="#00000000"
android:strokeColor="#EE5445"
android:strokeLineCap="round"/>
<path
android:pathData="M15.125,12.792L17.917,10L15.125,7.209"
android:strokeLineJoin="round"
android:strokeWidth="1.25"
android:fillColor="#00000000"
android:strokeColor="#EE5445"
android:strokeLineCap="round"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -0,0 +1,4 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/white" /> <!-- Set white color -->
<corners android:radius="8dp"/> <!-- Optional: Rounded corners -->
</shape>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white" />
<corners android:radius="@dimen/dp_8" />
<padding
android:left="@dimen/dp_16"
android:top="@dimen/dp_16"
android:right="@dimen/dp_16"
android:bottom="@dimen/dp_16" />
<stroke
android:width="@dimen/dp_1"
android:color="@color/outline_grey_color" />
</shape>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white" />
<corners android:radius="@dimen/dp_4" />
<padding
android:left="@dimen/dp_12"
android:top="@dimen/dp_12"
android:right="@dimen/dp_12"
android:bottom="@dimen/dp_12" />
<stroke
android:width="@dimen/dp_1"
android:color="@color/outline_grey_color" />
</shape>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="@dimen/dp_4" />
</shape>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/lightest_green" />
<corners android:radius="@dimen/dp_20" />
<padding
android:left="@dimen/dp_16"
android:top="@dimen/dp_8"
android:right="@dimen/dp_16"
android:bottom="@dimen/dp_8" />
</shape>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/main_color" />
<corners android:radius="@dimen/dp_8" />
<padding
android:left="@dimen/dp_4"
android:top="@dimen/dp_8"
android:right="@dimen/dp_4"
android:bottom="@dimen/dp_8" />
</shape>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke android:color="@color/main_color"
android:width="@dimen/dp_1"
/>
<corners android:radius="@dimen/dp_8" />
<padding
android:left="@dimen/dp_4"
android:top="@dimen/dp_8"
android:right="@dimen/dp_4"
android:bottom="@dimen/dp_8" />
</shape>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white" />
<corners android:radius="@dimen/dp_8" />
<padding
android:left="@dimen/dp_16"
android:top="@dimen/dp_8"
android:right="@dimen/dp_16"
android:bottom="@dimen/dp_8" />
<stroke
android:width="@dimen/dp_1"
android:color="@color/outline_grey_color" />
</shape>

View file

@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="14dp"
android:height="13dp"
android:viewportWidth="14"
android:viewportHeight="13">
<path
android:strokeWidth="1"
android:pathData="M13,12.5L10.105,9.605M10.105,9.605C10.6,9.11 10.993,8.522 11.261,7.874C11.529,7.227 11.667,6.534 11.667,5.833C11.667,5.133 11.529,4.44 11.261,3.792C10.993,3.145 10.6,2.557 10.105,2.062C9.61,1.567 9.022,1.174 8.375,0.906C7.727,0.638 7.034,0.5 6.333,0.5C5.633,0.5 4.94,0.638 4.292,0.906C3.645,1.174 3.057,1.567 2.562,2.062C1.562,3.062 1,4.419 1,5.833C1,7.248 1.562,8.605 2.562,9.605C3.562,10.605 4.919,11.167 6.333,11.167C7.748,11.167 9.105,10.605 10.105,9.605Z"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#285747"
android:strokeLineCap="round"/>
</vector>

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white" />
<corners android:topLeftRadius="@dimen/dp_8"
android:topRightRadius="@dimen/dp_8"
/>
<stroke
android:width="1.5dp"
android:color="@color/outline_greyish_color" />
</shape>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
tools:context=".ui.homescreen.HomeActivity">
<fragment
android:id="@+id/nav_host_fragment_content_main"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,152 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
tools:context=".ui.login.LoginActivity">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/topGuide"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.15" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/leftGuide"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="@dimen/dp_16" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/rightGuide"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_end="@dimen/dp_16" />
<ImageView
android:id="@+id/ivAppLogo"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_100"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/topGuide"
android:layout_marginStart="@dimen/dp_16"
android:layout_marginEnd="@dimen/dp_16"
android:src="@drawable/app_logo"/>
<TextView
android:id="@+id/txtSignIn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:text="@string/sign_in"
android:textSize="@dimen/sp_18"
android:fontFamily="@font/montserratbold"
app:layout_constraintTop_toBottomOf="@+id/ivAppLogo"
android:layout_marginTop="@dimen/dp_64"
/>
<TextView
android:id="@+id/txtSignInContinue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sign_in_to_continue"
app:layout_constraintStart_toStartOf="parent"
android:textColor="@color/black"
android:textSize="@dimen/sp_14"
android:fontFamily="@font/montserratregular"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/txtSignIn"
android:layout_marginTop="@dimen/dp_8"
/>
<EditText
android:id="@+id/etEmail"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="@id/leftGuide"
app:layout_constraintEnd_toStartOf="@id/rightGuide"
app:layout_constraintTop_toBottomOf="@+id/txtSignInContinue"
android:hint="@string/email_address"
android:textSize="@dimen/sp_14"
android:textColor="@color/edit_text_color"
android:fontFamily="@font/montserratregular"
android:layout_marginTop="@dimen/dp_36"
android:background="@drawable/rounded_background"
android:maxLines="1"
android:inputType="textEmailAddress"
android:singleLine="true"
android:imeOptions="actionDone"
/>
<!-- <EditText
android:id="@+id/etPassword"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:autofillHints=""
app:layout_constraintStart_toEndOf="@id/leftGuide"
app:layout_constraintEnd_toStartOf="@id/rightGuide"
app:layout_constraintTop_toBottomOf="@+id/etEmail"
android:hint="@string/password"
android:textSize="@dimen/sp_14"
android:fontFamily="@font/montserratregular"
android:textColor="@color/edit_text_color"
android:layout_marginTop="@dimen/dp_16"
android:background="@drawable/rounded_background"
/>-->
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilPassword"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:endIconMode="password_toggle"
android:layout_marginTop="@dimen/dp_16"
app:layout_constraintStart_toEndOf="@id/leftGuide"
app:layout_constraintEnd_toStartOf="@id/rightGuide"
app:layout_constraintTop_toBottomOf="@+id/etEmail"
app:hintEnabled="false"
>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:textColor="@color/edit_text_color"
android:textSize="@dimen/sp_14"
android:maxLines="1"
android:singleLine="true"
android:hint="@string/password"
android:imeOptions="actionDone"
android:fontFamily="@font/montserratregular"
android:background="@drawable/rounded_background" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/btnSigIn"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="@id/leftGuide"
app:layout_constraintEnd_toStartOf="@id/rightGuide"
android:textSize="@dimen/sp_16"
app:layout_constraintTop_toBottomOf="@+id/tilPassword"
android:layout_marginTop="@dimen/dp_28"
android:text="@string/sign_in"
android:paddingTop="@dimen/dp_10"
android:paddingBottom="@dimen/dp_10"
android:fontFamily="@font/montserratsemibold"
android:background="@drawable/rounded_background"
android:textColor="#FFFFFF"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" />
</com.google.android.material.appbar.AppBarLayout>
<include layout="@layout/content_main" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginEnd="@dimen/fab_margin"
android:layout_marginBottom="16dp"
app:srcCompat="@android:drawable/ic_dialog_email" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

Some files were not shown because too many files have changed in this diff Show more