diff --git a/.circleci/config.yml b/.circleci/config.yml
index 9d82d27..60faab9 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -7,8 +7,135 @@ version: 2.1
# Orbs are reusable packages of CircleCI configuration that you may share across projects, enabling you to create encapsulated, parameterized commands, jobs, and executors that can be used across multiple projects.
# See: https://circleci.com/docs/2.0/orb-intro/
orbs:
- android: circleci/android@1.0.3
+ android: circleci/android@2.3.0
+commands:
+ setup_repo:
+ description: checkout repo and android dependencies
+ steps:
+ - checkout
+ # Setup files for build.
+ - run:
+ name: Setup variables for build
+ command: |
+ echo "$GOOGLE_SERVICES_KEY" > "app/google-services.json"
+ - android/restore-gradle-cache
+ build_gradle:
+ description: Build the gradle
+ steps:
+ - android/restore-gradle-cache
+ - run:
+ name: Download Dependencies
+ command: |
+ sudo chmod +x ./gradlew
+ ./gradlew androidDependencies
+ - android/save-gradle-cache
+ run_tests:
+ description: run non-instrumentation tests for flavour specified
+ parameters:
+ flavour:
+ type: string
+ default: "Driver"
+ steps:
+ # The next step will run the unit tests
+ - build_gradle
+ - run:
+ name: Run non-instrumentation unit tests
+ command: |
+ ./gradlew test<< parameters.flavour >>DebugUnitTest --continue
+ - store_artifacts:
+ path: app/build/reports
+ destination: reports
+ - store_test_results:
+ path: app/build/test-results
+ run_ui_tests:
+ description: start firebase emulator and run ui tests for flavour specified
+ parameters:
+ flavour:
+ type: string
+ default: "AtlasWeather"
+ steps:
+ # Download and cache dependencies
+ - build_gradle
+ - run:
+ name: Setup subtree for test data
+ command: |
+ git stash
+ git config --global user.email "$GIT_EMAIL"
+ git config --global user.name "$GIT_EMAIL"
+ git remote add -f driver_app_data https://github.com/hmalik144/driver_app_data.git
+ git subtree add --prefix=driver_app_data driver_app_data main --squash
+ - restore_cache:
+ keys:
+ - emulator-cache-v1-
+ # Install Firebase tools needed for firebase emulator
+ - run:
+ name: Install firebase tools
+ command: |
+ curl -sL firebase.tools | bash
+ # Then start the emulator and run the Instrumentation tests!
+ - android/start-emulator-and-run-tests:
+ post-emulator-launch-assemble-command: ./gradlew assemble<< parameters.flavour >>DebugAndroidTest
+ test-command: ./gradlew connected<< parameters.flavour >>DebugAndroidTest
+ system-image: system-images;android-25;google_apis;x86
+ pull-data: true
+ pull-data-path: /storage/emulated/0/Android/data/
+ pull-data-target: ~/app-data
+ pre-emulator-wait-steps:
+ # Start firebase emulator in the background while waiting to start testing
+ - run:
+ name: Start firebase emulator and while avd starts
+ command: |
+ firebase emulators:start --import=driver_app_data/export_directory
+ background: true
+ post-run-tests-steps:
+ # Save cache for firebase tools
+ - save_cache:
+ paths:
+ - ~/.cache/firebase/emulators/
+ key: emulator-cache-v1-{{ epoch }}
+ # store test reports
+ - store_artifacts:
+ path: app/build/reports/androidTests/connected
+ destination: reports
+ # store screenshots for failed ui tests
+ - store_artifacts:
+ path: ~/app-data
+ destination: data
+ # Then publish the artifacts of the Firebase emulator logs!
+ - run:
+ name: save firebase emulator logs
+ command: |
+ mkdir -p tmp/firebase_logs
+ cp *.log tmp/firebase_logs
+ - store_artifacts:
+ path: tmp/firebase_logs
+ destination: logs
+ # Then publish the results of the Instrumentation tests!
+ - store_test_results:
+ path: app/build/outputs/androidTest-results/connected
+ deploy_to_play_store:
+ description: deploy to playstore based on flavour
+ parameters:
+ flavour:
+ type: string
+ default: "Driver"
+ steps:
+ # The next step will run the unit tests
+ - android/decode-keystore:
+ keystore-location: "./app/keystore.jks"
+ - run:
+ name: Setup playstore key
+ command: |
+ echo "$GOOGLE_PLAY_KEY" > "google-play-key.json"
+ - build_gradle
+ - run:
+ name: Run fastlane command to deploy to playstore
+ command: |
+ pwd
+ bundle exec fastlane deploy<< parameters.flavour >>
+ - store_test_results:
+ path: fastlane/report.xml
# Define a job to be invoked later in a workflow.
# See: https://circleci.com/docs/2.0/configuration-reference/#jobs
jobs:
@@ -23,76 +150,30 @@ jobs:
# See: https://circleci.com/docs/2.0/executor-types/
executor:
name: android/android-machine
-
+ tag: 2023.05.1
# Add steps to the job
# See: https://circleci.com/docs/2.0/configuration-reference/#steps
steps:
- # Checkout the code as the first step.
- - checkout
- # Setup files for build.
- - run:
- name: Setup variables for build
- command: |
- echo "$GOOGLE_SERVICES_KEY" > "app/google-services.json"
- - run:
- name: Grant execute permission for gradlew
- command: |
- chmod +x gradlew
- # The next step will run the unit tests
- - android/run-tests:
- test-command: ./gradlew test<< parameters.flavour >>DebugUnitTest --continue
- # Install Firebase tools needed for firebase emulator
- - run:
- name: Install firebase tools
- command: |
- curl -sL firebase.tools | bash
- # Then start firebase emulator in the background
- - run:
- name: Start firebase emulator
- command: |
- firebase emulators:start
- background: true
- # Then start the emulator and run the Instrumentation tests!
- - android/start-emulator-and-run-tests:
- post-emulator-launch-assemble-command: ./gradlew assemble<< parameters.flavour >>DebugAndroidTest
- test-command: ./gradlew connected<< parameters.flavour >>DebugAndroidTest
- system-image: system-images;android-25;google_apis;x86
- # store test reports
- - store_artifacts:
- path: app/build/reports/androidTests/connected
- destination: reports
- # Then publish the artifacts of the Firebase emulator logs!
- - run:
- name: save firebase emulator logs
- command: |
- mkdir -p tmp/firebase_logs
- cp *.log tmp/firebase_logs
- - store_artifacts:
- path: tmp/firebase_logs
- destination: logs
- # Then publish the results of the Instrumentation tests!
- - store_test_results:
- path: app/build/outputs/androidTest-results/connected
- # Assemble
- assemble-and-release:
- # Parameters used for determining
+ # Checkout the code and its submodule as the first step.
+ - setup_repo
+# - run_tests:
+# flavour: << parameters.flavour >>
+ - run_ui_tests:
+ flavour: << parameters.flavour >>
+ deploy-to-playstore:
parameters:
flavour:
type: string
- default: ""
- executor:
- name: android/android-machine
+ default: "Driver"
+ docker:
+ - image: cimg/android:2023.07-browsers
+ auth:
+ username: ${DOCKER_USERNAME}
+ password: ${DOCKER_PASSWORD}
steps:
- - run:
- name: Setup variables for release
- command: |
- echo "$RELEASE_KEYSTORE_BASE64" | base64 --decode > "android/app/release_keystore.jks"
- echo "$GOOGLE_PLAY_KEY" > "android/playstore.json"
- # And finally run the release build
- - run:
- name: Assemble release build
- command: |
- ./gradlew assembleDriverRelease
+ - setup_repo
+ - deploy_to_play_store:
+ flavour: << parameters.flavour >>
# Invoke jobs via workflows
# See: https://circleci.com/docs/2.0/configuration-reference/#workflows
workflows:
@@ -100,8 +181,14 @@ workflows:
build-release-driver:
jobs:
- build-and-test:
- flavour: Driver
- - assemble-and-release:
+ context: appttude
+ flavour: "Driver"
+ filters:
+ branches:
+ ignore:
+ - main_admin
+ - deploy-to-playstore:
+ context: appttude
flavour: "Driver"
filters:
branches:
@@ -112,11 +199,18 @@ workflows:
build-release-admin:
jobs:
- build-and-test:
- flavour: Admin
- - assemble-and-release:
- flavour: Admin
+ context: appttude
+ flavour: "Admin"
filters:
branches:
- only: main_admin
+ ignore:
+ - main_driver
+ - deploy-to-playstore:
+ context: appttude
+ flavour: "Admin"
+ filters:
+ branches:
+ only:
+ - main_admin
requires:
- build-and-test
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 0fc0baf..ab59a65 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,9 +9,21 @@
/.idea/navEditor.xml
/.idea/misc.xml
/.idea/assetWizardSettings.xml
+/.idea/shelf/
.DS_Store
/build
/captures
.externalNativeBuild
*.log
local
+# Circleci
+/.circleci/local_config.yml
+/.circleci/run_local.bash
+# Gem/fastlane
+/Gemfile.lock
+/google-play-key.json
+/app/google-services.json
+/fastlane/report.xml
+# Firebase emulator
+database-debug.log
+firebase-debug.log
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
deleted file mode 100644
index b589d56..0000000
--- a/.idea/compiler.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/dictionaries/h_mal.xml b/.idea/dictionaries/h_mal.xml
deleted file mode 100644
index a2afb5c..0000000
--- a/.idea/dictionaries/h_mal.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
- viewmodel
-
-
-
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
deleted file mode 100644
index 66ff961..0000000
--- a/.idea/gradle.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index 6626cd0..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 35eb1dd..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..7a118b4
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,3 @@
+source "https://rubygems.org"
+
+gem "fastlane"
diff --git a/app/build.gradle b/app/build.gradle
index db9d346..460167c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -9,7 +9,9 @@ plugins {
def relStorePassword = System.getenv("RELEASE_STORE_PASSWORD")
def relKeyPassword = System.getenv("RELEASE_KEY_PASSWORD")
def relKeyAlias = System.getenv("RELEASE_KEY_ALIAS")
-def relStoreFile = System.getenv("RELEASE_KEYSTORE")
+
+def keystorePath = System.getenv('PWD') + "/app/keystore.jks"
+def keystore = file(keystorePath).exists() ? file(keystorePath) : null
android {
compileSdkVersion 31
@@ -17,8 +19,8 @@ android {
applicationId "h_mal.appttude.com.driver"
minSdkVersion 24
targetSdkVersion 31
- versionCode 6
- versionName "1.6"
+ versionCode 7
+ versionName "2.0.0"
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
boolean state = project.rootProject.file('local.properties').canRead()
@@ -41,7 +43,7 @@ android {
storePassword relStorePassword
keyPassword relKeyPassword
keyAlias relKeyAlias
-// storeFile file(relStoreFile)
+ storeFile keystore
}
}
@@ -66,22 +68,25 @@ android {
flavorDimensions "Default"
productFlavors {
driver {
- versionCode 6
- versionName "1.0.5"
+ applicationId "h_mal.appttude.com.driver"
+ versionCode 7
+ versionName "2.0.0"
}
admin {
- applicationIdSuffix ".admin"
+ applicationId "h_mal.appttude.com.driver.admin"
versionCode 4
versionName "0.0.5"
}
}
sourceSets {
driver {
+ java.srcDirs += 'src/driver/java'
manifest {
srcFile 'src/driver/AndroidManifest.xml'
}
}
admin {
+ java.srcDirs += 'src/admin/java'
manifest {
srcFile 'src/admin/AndroidManifest.xml'
}
@@ -108,6 +113,7 @@ dependencies {
implementation 'androidx.viewpager:viewpager:1.0.0'
implementation "androidx.legacy:legacy-support-v4:1.0.0"
testImplementation "junit:junit:4.13.2"
+ implementation "androidx.preference:preference-ktx:1.2.0"
/ * Android Espresso */
def testJunitVersion = "1.1.5"
def testRunnerVersion = "1.5.2"
@@ -117,6 +123,8 @@ dependencies {
androidTestImplementation "androidx.test.espresso.idling:idling-concurrent:$espressoVersion"
implementation "androidx.test.espresso:espresso-idling-resource:$espressoVersion"
androidTestImplementation "androidx.test:runner:$testRunnerVersion"
+ androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion"
+ androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion"
/ * Google play services */
implementation "com.google.android.gms:play-services-auth:20.4.1"
/ * Google firebase */
@@ -128,6 +136,7 @@ dependencies {
implementation "com.google.firebase:firebase-auth:$firebaseAuth"
implementation "com.google.firebase:firebase-storage:$firebaseStorage"
implementation "com.google.firebase:firebase-database:$firebaseDatabase"
+ implementation 'com.firebaseui:firebase-ui-database:8.0.2'
/ * Photoviewer */
implementation "com.github.chrisbanes:PhotoView:2.1.0"
/ * Picasso photo loader */
@@ -151,4 +160,10 @@ dependencies {
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
/ * Kotlin Reflect */
implementation "org.jetbrains.kotlin:kotlin-reflect:1.8.10"
+ / * Retrofit2 */
+ def retrofit_version = "2.9.0"
+ androidTestImplementation "com.squareup.retrofit2:retrofit:$retrofit_version"
+ androidTestImplementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
+ / * screenshot library */
+ androidTestImplementation 'tools.fastlane:screengrab:2.1.1'
}
diff --git a/app/src/admin/AndroidManifest.xml b/app/src/admin/AndroidManifest.xml
deleted file mode 100644
index 0dd5de2..0000000
--- a/app/src/admin/AndroidManifest.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/application/ApplicationViewModelFactory.kt b/app/src/admin/java/h_mal/appttude/com/driver/application/ApplicationViewModelFactory.kt
new file mode 100644
index 0000000..6bb156a
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/application/ApplicationViewModelFactory.kt
@@ -0,0 +1,68 @@
+package h_mal.appttude.com.driver.application
+
+import android.content.res.Resources
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import h_mal.appttude.com.driver.data.FirebaseAuthSource
+import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
+import h_mal.appttude.com.driver.data.FirebaseStorageSource
+import h_mal.appttude.com.driver.data.prefs.PreferenceProvider
+import h_mal.appttude.com.driver.viewmodels.*
+
+class ApplicationViewModelFactory(
+ private val auth: FirebaseAuthSource,
+ private val database: FirebaseDatabaseSource,
+ private val storage: FirebaseStorageSource,
+ private val preferences: PreferenceProvider,
+ private val resources: Resources
+) : ViewModelProvider.Factory {
+
+ @Suppress("UNCHECKED_CAST")
+ override fun create(modelClass: Class): T {
+ with(modelClass) {
+ return when {
+ isAssignableFrom(UserViewModel::class.java) -> UserViewModel(auth)
+ isAssignableFrom(MainViewModel::class.java) -> MainViewModel(auth, database)
+ isAssignableFrom(UpdateUserViewModel::class.java) -> UpdateUserViewModel(
+ auth,
+ storage
+ )
+ isAssignableFrom(RoleViewModel::class.java) -> RoleViewModel(
+ auth,
+ database,
+ storage
+ )
+
+ isAssignableFrom(DriverLicenseViewModel::class.java) -> DriverLicenseViewModel(
+ database
+ )
+ isAssignableFrom(DriverProfileViewModel::class.java) -> DriverProfileViewModel(
+ database
+ )
+ isAssignableFrom(PrivateHireLicenseViewModel::class.java) -> PrivateHireLicenseViewModel(
+ database
+ )
+ isAssignableFrom(VehicleProfileViewModel::class.java) -> VehicleProfileViewModel(
+ database
+ )
+ isAssignableFrom(InsuranceViewModel::class.java) -> InsuranceViewModel(database)
+ isAssignableFrom(MotViewModel::class.java) -> MotViewModel(database)
+ isAssignableFrom(LogbookViewModel::class.java) -> LogbookViewModel(database)
+ isAssignableFrom(PrivateHireVehicleViewModel::class.java) -> PrivateHireVehicleViewModel(
+ database
+ )
+ isAssignableFrom(DriverOverviewViewModel::class.java) -> DriverOverviewViewModel(
+ auth,
+ database
+ )
+ isAssignableFrom(SuperUserViewModel::class.java) -> SuperUserViewModel(
+ database,
+ preferences
+ )
+ isAssignableFrom(ApproverViewModel::class.java) -> ApproverViewModel(resources , database)
+ else -> throw IllegalArgumentException("Unknown ViewModel class")
+ } as T
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/application/DriverApplication.kt b/app/src/admin/java/h_mal/appttude/com/driver/application/DriverApplication.kt
new file mode 100644
index 0000000..6f4a8b6
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/application/DriverApplication.kt
@@ -0,0 +1,23 @@
+package h_mal.appttude.com.driver.application
+
+import h_mal.appttude.com.driver.data.prefs.PreferenceProvider
+import org.kodein.di.generic.bind
+import org.kodein.di.generic.instance
+import org.kodein.di.generic.provider
+import org.kodein.di.generic.singleton
+
+class DriverApplication : BaseApplication() {
+
+ override val flavourModule = super.flavourModule.copy {
+ bind() from singleton { PreferenceProvider(this@DriverApplication) }
+ bind() from provider {
+ ApplicationViewModelFactory(
+ instance(),
+ instance(),
+ instance(),
+ instance(),
+ instance()
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/base/DataViewerBaseViewModel.kt b/app/src/admin/java/h_mal/appttude/com/driver/base/DataViewerBaseViewModel.kt
new file mode 100644
index 0000000..f0dcb82
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/base/DataViewerBaseViewModel.kt
@@ -0,0 +1,40 @@
+package h_mal.appttude.com.driver.base
+
+import com.google.firebase.database.DatabaseReference
+import h_mal.appttude.com.driver.data.FirebaseCompletion
+import h_mal.appttude.com.driver.utils.Coroutines.io
+import h_mal.appttude.com.driver.utils.GenericsHelper.getGenericClassAt
+import h_mal.appttude.com.driver.utils.getDataFromDatabaseRef
+import h_mal.appttude.com.driver.utils.isNotNull
+
+abstract class DataViewerBaseViewModel : BaseViewModel() {
+ var uid: String? = null
+
+ abstract fun getDatabaseRef(uid: String): DatabaseReference
+
+ fun initViewModel(uid: String) {
+ this.uid = uid
+ retrieveData(uid)
+ }
+
+ fun fetchData() {
+ @Suppress("IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION")
+ uid.isNotNull {
+ retrieveData(it)
+ return
+ }
+
+ onError("Failed to retrieve data for user")
+ }
+
+ private fun retrieveData(uid: String) {
+ val clazz = getGenericClassAt(0)
+ io {
+ doTryOperation("Failed to retrieve ${clazz.simpleName}") {
+ val data = getDatabaseRef(uid).getDataFromDatabaseRef(clazz.java)
+ onSuccess(data ?: FirebaseCompletion.Default)
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/base/DataViewerFragment.kt b/app/src/admin/java/h_mal/appttude/com/driver/base/DataViewerFragment.kt
new file mode 100644
index 0000000..3d991aa
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/base/DataViewerFragment.kt
@@ -0,0 +1,55 @@
+package h_mal.appttude.com.driver.base
+
+import android.view.View
+import android.view.ViewGroup
+import android.widget.CheckBox
+import android.widget.EditText
+import androidx.core.view.children
+import androidx.viewbinding.ViewBinding
+import h_mal.appttude.com.driver.data.USER_CONST
+import h_mal.appttude.com.driver.utils.GenericsHelper.getGenericClassAt
+import h_mal.appttude.com.driver.utils.hide
+import h_mal.appttude.com.driver.utils.isTrue
+
+open class DataViewerFragment, VB : ViewBinding, T : Any> :
+ BaseFragment() {
+
+ override fun setupView(binding: VB) {
+ super.setupView(binding)
+
+ (binding.root as ViewGroup).children.forEach { disableViews(it) }
+ }
+
+ private fun disableViews(view: View) {
+ if (view is EditText)
+ view.isFocusable = false
+ if (view is CheckBox)
+ view.isFocusable = false
+ else if (view is ViewGroup)
+ view.children.forEach { disableViews(it) }
+ }
+
+ override fun onStart() {
+ super.onStart()
+ requireArguments().getString(USER_CONST)?.let {
+ viewModel.initViewModel(it)
+ }
+ }
+
+
+ @Suppress("UNCHECKED_CAST")
+ override fun onSuccess(data: Any?) {
+ super.onSuccess(data)
+
+ data?.let { (data::class == getGenericClassAt(2)) }?.isTrue {
+ setFields(data as T)
+ }
+ }
+
+ open fun setFields(data: T) {}
+
+ fun viewsToHide(vararg view: View) {
+ view.forEach { it.hide() }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/model/ApprovalStatus.kt b/app/src/admin/java/h_mal/appttude/com/driver/model/ApprovalStatus.kt
new file mode 100644
index 0000000..75fc57b
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/model/ApprovalStatus.kt
@@ -0,0 +1,19 @@
+package h_mal.appttude.com.driver.model
+
+import h_mal.appttude.com.driver.R
+
+enum class ApprovalStatus(val stringId: Int, val drawableId: Int, val score: Int) {
+ NOT_SUBMITTED(R.string.not_submitted, R.drawable.denied, 0),
+ DENIED(R.string.denied, R.drawable.denied, 1),
+ PENDING_APPROVAL(R.string.pending, R.drawable.pending, 2),
+ APPROVED(R.string.approved, R.drawable.approved, 3);
+
+ companion object {
+ infix fun getByScore(value: Int): ApprovalStatus? =
+ ApprovalStatus.values().firstOrNull { it.score == value }
+ infix fun getByStringId(value: Int): ApprovalStatus? =
+ ApprovalStatus.values().firstOrNull { it.stringId == value }
+ infix fun getByDrawableId(value: Int): ApprovalStatus? =
+ ApprovalStatus.values().firstOrNull { it.drawableId == value }
+ }
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/model/DatabaseStatus.kt b/app/src/admin/java/h_mal/appttude/com/driver/model/DatabaseStatus.kt
new file mode 100644
index 0000000..3fba046
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/model/DatabaseStatus.kt
@@ -0,0 +1,27 @@
+package h_mal.appttude.com.driver.model
+
+import h_mal.appttude.com.driver.R
+
+enum class DatabaseStatus(val drawable: Int, val header: Int, val subtext: Int) {
+ NO_CONNECTION(R.drawable.baseline_inbox_24, R.string.no_connection, R.string.no_connection_subtext),
+ NO_PERMISSION(
+ R.drawable.baseline_inbox_24,
+ R.string.no_permission,
+ R.string.no_permission_subtext
+ ),
+ CANNOT_RETRIEVE(
+ R.drawable.baseline_inbox_24,
+ R.string.cannot_retrieve,
+ R.string.cannot_retrieve_subtext
+ ),
+ NO_AUTHORIZATION(
+ R.drawable.baseline_inbox_24,
+ R.string.no_authorization,
+ R.string.no_authorization_subtext
+ ),
+ EMPTY_RESULTS(
+ R.drawable.baseline_inbox_24,
+ R.string.no_drivers_to_show,
+ R.string.no_drivers_subtext
+ )
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/model/SortOption.kt b/app/src/admin/java/h_mal/appttude/com/driver/model/SortOption.kt
new file mode 100644
index 0000000..d51c199
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/model/SortOption.kt
@@ -0,0 +1,17 @@
+package h_mal.appttude.com.driver.model
+
+enum class SortOption(val key: String, val label: String) {
+ NAME("driver_profile/driver_details/forenames","Driver Name"),
+ NUMBER("driver_number", "Driver Number");
+// APPROVAL("forenames")
+
+ companion object {
+ fun getSortOptionByLabel(label: String?): SortOption? {
+ return values().firstOrNull { i -> i.label == label }
+ }
+ fun getPositionByLabel(label: String?): Int? {
+ val sortOption = getSortOptionByLabel(label) ?: return null
+ return values().indexOf(sortOption)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/objects/ApprovalsObject.kt b/app/src/admin/java/h_mal/appttude/com/driver/objects/ApprovalsObject.kt
index 515307e..47a4493 100644
--- a/app/src/admin/java/h_mal/appttude/com/driver/objects/ApprovalsObject.kt
+++ b/app/src/admin/java/h_mal/appttude/com/driver/objects/ApprovalsObject.kt
@@ -1,34 +1,13 @@
-package h_mal.appttude.com.driver.admin.objects
+package h_mal.appttude.com.driver.objects
-class ApprovalsObject {
- var driver_details_approval: Int = 0
- var driver_license_approval: Int = 0
- var private_hire_approval: Int = 0
- var vehicle_details_approval: Int = 0
- var mot_details_approval: Int = 0
- var insurance_details_approval: Int = 0
- var log_book_approval: Int = 0
- var ph_car_approval: Int = 0
-
- constructor()
- constructor(
- driver_details_approval: Int,
- driver_license_approval: Int,
- private_hire_approval: Int,
- vehicle_details_approval: Int,
- mot_details_approval: Int,
- insurance_details_approval: Int,
- log_book_approval: Int,
- private_hire_vehicle_approval: Int
- ) {
- this.driver_details_approval = driver_details_approval
- this.driver_license_approval = driver_license_approval
- this.private_hire_approval = private_hire_approval
- this.vehicle_details_approval = vehicle_details_approval
- this.mot_details_approval = mot_details_approval
- this.insurance_details_approval = insurance_details_approval
- this.log_book_approval = log_book_approval
- this.ph_car_approval = private_hire_vehicle_approval
- }
-}
\ No newline at end of file
+data class ApprovalsObject (
+ var driver_details_approval: Int = 0,
+ var driver_license_approval: Int = 0,
+ var private_hire_approval: Int = 0,
+ var vehicle_details_approval: Int = 0,
+ var mot_details_approval: Int = 0,
+ var insurance_details_approval: Int = 0,
+ var log_book_approval: Int = 0,
+ var ph_car_approval: Int = 0,
+)
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/objects/ArchiveObject.kt b/app/src/admin/java/h_mal/appttude/com/driver/objects/ArchiveObject.kt
index 6595886..2700e93 100644
--- a/app/src/admin/java/h_mal/appttude/com/driver/objects/ArchiveObject.kt
+++ b/app/src/admin/java/h_mal/appttude/com/driver/objects/ArchiveObject.kt
@@ -1,33 +1,20 @@
-package h_mal.appttude.com.driver.admin.objects
+package h_mal.appttude.com.driver.objects
-import h_mal.appttude.com.driver.model.*
-import java.util.*
+import h_mal.appttude.com.driver.model.DriversLicense
+import h_mal.appttude.com.driver.model.Insurance
+import h_mal.appttude.com.driver.model.Logbook
+import h_mal.appttude.com.driver.model.Mot
+import h_mal.appttude.com.driver.model.PrivateHireLicense
+import h_mal.appttude.com.driver.model.PrivateHireVehicle
+import h_mal.appttude.com.driver.model.VehicleProfile
-class ArchiveObject {
- var driver_license: HashMap? = null
- var private_hire: HashMap? = null
- var vehicle_details: HashMap? = null
- var insurance_details: HashMap? = null
- var mot_details: HashMap? = null
- var log_book: HashMap? = null
- var ph_car: HashMap? = null
- constructor()
- constructor(
- driver_license: HashMap?,
- private_hire: HashMap?,
- vehicle_details: HashMap?,
- insurance_details: HashMap?,
- mot_details: HashMap?,
- log_book: HashMap?,
- private_hire_vehicle: HashMap?
- ) {
- this.driver_license = driver_license
- this.private_hire = private_hire
- this.vehicle_details = vehicle_details
- this.insurance_details = insurance_details
- this.mot_details = mot_details
- this.log_book = log_book
- this.ph_car = private_hire_vehicle
- }
-}
\ No newline at end of file
+data class ArchiveObject(
+ var driver_license: HashMap? = HashMap(),
+ var private_hire: HashMap? = HashMap(),
+ var vehicle_details: HashMap? = HashMap(),
+ var insurance_details: HashMap? = HashMap(),
+ var mot_details: HashMap? = HashMap(),
+ var log_book: HashMap? = HashMap(),
+ var ph_car: HashMap? = HashMap(),
+)
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/objects/UserObject.kt b/app/src/admin/java/h_mal/appttude/com/driver/objects/UserObject.kt
index 918d377..a2c3c12 100644
--- a/app/src/admin/java/h_mal/appttude/com/driver/objects/UserObject.kt
+++ b/app/src/admin/java/h_mal/appttude/com/driver/objects/UserObject.kt
@@ -1,15 +1,10 @@
-package h_mal.appttude.com.driver.admin.objects
+package h_mal.appttude.com.driver.objects
+import com.google.firebase.database.IgnoreExtraProperties
-class UserObject {
- var profileName: String? = null
- var profileEmail: String? = null
- var profilePicString: String? = null
-
- constructor()
- constructor(profileName: String?, profileEmail: String?, profilePicString: String?) {
- this.profileName = profileName
- this.profileEmail = profileEmail
- this.profilePicString = profilePicString
- }
-}
\ No newline at end of file
+@IgnoreExtraProperties
+data class UserObject (
+ var profileName: String? = "",
+ var profileEmail: String? = "",
+ var profilePicString: String? = "",
+)
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/objects/WholeDriverObject.kt b/app/src/admin/java/h_mal/appttude/com/driver/objects/WholeDriverObject.kt
index 727e872..dd68623 100644
--- a/app/src/admin/java/h_mal/appttude/com/driver/objects/WholeDriverObject.kt
+++ b/app/src/admin/java/h_mal/appttude/com/driver/objects/WholeDriverObject.kt
@@ -1,35 +1,15 @@
-package h_mal.appttude.com.driver.admin.objects
+package h_mal.appttude.com.driver.objects
-import h_mal.appttude.com.driver.admin.objects.wholeObject.DriverProfile
-import h_mal.appttude.com.driver.admin.objects.wholeObject.VehicleProfile
+import h_mal.appttude.com.driver.objects.wholeObject.DriverProfile
+import h_mal.appttude.com.driver.objects.wholeObject.VehicleProfile
-class WholeDriverObject {
- var driver_profile: DriverProfile? = null
- var role: String? = null
- var archive: ArchiveObject? = null
- var user_details: UserObject? = null
- var vehicle_profile: VehicleProfile? = null
- var approvalsObject: ApprovalsObject? = null
- var driver_number: String? = null
-
- constructor(
- driver_profile: DriverProfile?,
- role: String?,
- archive: ArchiveObject?,
- user_details: UserObject?,
- vehicle_profile: VehicleProfile?,
- approvalsObject: ApprovalsObject?,
- driver_number: String?
- ) {
- this.driver_profile = driver_profile
- this.role = role
- this.archive = archive
- this.user_details = user_details
- this.vehicle_profile = vehicle_profile
- this.approvalsObject = approvalsObject
- this.driver_number = driver_number
- }
-
- constructor()
-}
\ No newline at end of file
+data class WholeDriverObject(
+ var driver_profile: DriverProfile? = DriverProfile(),
+ var role: String? = "",
+ var archive: ArchiveObject? = ArchiveObject(),
+ var user_details: UserObject? = UserObject(),
+ var vehicle_profile: VehicleProfile? = VehicleProfile(),
+ var approvalsObject: ApprovalsObject? = ApprovalsObject(),
+ var driver_number: String? = "",
+)
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/objects/wholeObject/DriverProfile.kt b/app/src/admin/java/h_mal/appttude/com/driver/objects/wholeObject/DriverProfile.kt
index 36ffc4b..26f47ee 100644
--- a/app/src/admin/java/h_mal/appttude/com/driver/objects/wholeObject/DriverProfile.kt
+++ b/app/src/admin/java/h_mal/appttude/com/driver/objects/wholeObject/DriverProfile.kt
@@ -1,24 +1,12 @@
-package h_mal.appttude.com.driver.admin.objects.wholeObject
+package h_mal.appttude.com.driver.objects.wholeObject
import h_mal.appttude.com.driver.model.DriverProfile
import h_mal.appttude.com.driver.model.DriversLicense
import h_mal.appttude.com.driver.model.PrivateHireLicense
-class DriverProfile {
- var driver_profile: DriverProfile? = null
- var driver_license: DriversLicense? = null
- var private_hire: PrivateHireLicense? = null
-
- constructor(
- driver_profile: DriverProfile?,
- driver_license: DriversLicense?,
- private_hire: PrivateHireLicense?
- ) {
- this.driver_profile = driver_profile
- this.driver_license = driver_license
- this.private_hire = private_hire
- }
-
- constructor()
-}
\ No newline at end of file
+data class DriverProfile(
+ var driver_profile: DriverProfile? = DriverProfile(),
+ var driver_license: DriversLicense? = DriversLicense(),
+ var private_hire: PrivateHireLicense? = PrivateHireLicense(),
+)
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/objects/wholeObject/MappedObject.kt b/app/src/admin/java/h_mal/appttude/com/driver/objects/wholeObject/MappedObject.kt
deleted file mode 100644
index 20649ed..0000000
--- a/app/src/admin/java/h_mal/appttude/com/driver/objects/wholeObject/MappedObject.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-package h_mal.appttude.com.driver.admin.objects.wholeObject
-
-import android.os.Parcel
-import android.os.Parcelable
-import h_mal.appttude.com.driver.admin.objects.WholeDriverObject
-
-
-class MappedObject : Parcelable {
- var userId: String? = null
- var wholeDriverObject: WholeDriverObject? = null
-
- constructor(userId: String?, wholeDriverObject: WholeDriverObject?) {
- this.userId = userId
- this.wholeDriverObject = wholeDriverObject
- }
-
- constructor()
- protected constructor(`in`: Parcel) {
- userId = `in`.readString()
- }
-
- override fun describeContents(): Int {
- return 0
- }
-
- override fun writeToParcel(dest: Parcel, flags: Int) {
- dest.writeString(userId)
- }
-
- companion object {
- @JvmField
- val CREATOR: Parcelable.Creator =
- object : Parcelable.Creator {
- override fun createFromParcel(`in`: Parcel): MappedObject? {
- return MappedObject(`in`)
- }
-
- override fun newArray(size: Int): Array {
- return arrayOfNulls(size)
- }
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/objects/wholeObject/VehicleProfile.kt b/app/src/admin/java/h_mal/appttude/com/driver/objects/wholeObject/VehicleProfile.kt
index e2f3a26..1828463 100644
--- a/app/src/admin/java/h_mal/appttude/com/driver/objects/wholeObject/VehicleProfile.kt
+++ b/app/src/admin/java/h_mal/appttude/com/driver/objects/wholeObject/VehicleProfile.kt
@@ -1,31 +1,15 @@
-package h_mal.appttude.com.driver.admin.objects.wholeObject
+package h_mal.appttude.com.driver.objects.wholeObject
import h_mal.appttude.com.driver.model.Insurance
import h_mal.appttude.com.driver.model.Logbook
-import h_mal.appttude.com.driver.model.PrivateHireVehicle
import h_mal.appttude.com.driver.model.Mot
+import h_mal.appttude.com.driver.model.PrivateHireVehicle
import h_mal.appttude.com.driver.model.VehicleProfile
-
-class VehicleProfile {
- var insurance_details: Insurance? = null
- var log_book: Logbook? = null
- var mot_details: Mot? = null
- var vehicle_details: VehicleProfile? = null
- var privateHireVehicle: PrivateHireVehicle? = null
-
- constructor()
- constructor(
- insurance_details: Insurance?,
- log_book: Logbook?,
- mot_details: Mot?,
- vehicle_details: VehicleProfile?,
- private_hire_vehicle: PrivateHireVehicle?
- ) {
- this.insurance_details = insurance_details
- this.log_book = log_book
- this.mot_details = mot_details
- this.vehicle_details = vehicle_details
- this.privateHireVehicle = private_hire_vehicle
- }
-}
\ No newline at end of file
+data class VehicleProfile (
+ var insurance_details: Insurance? = Insurance(),
+ var log_book: Logbook? = Logbook(),
+ var mot_details: Mot? = Mot(),
+ var vehicle_details: VehicleProfile? = VehicleProfile(),
+ var privateHireVehicle: PrivateHireVehicle? = PrivateHireVehicle()
+)
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/ui/ApprovalListAdapter.kt b/app/src/admin/java/h_mal/appttude/com/driver/ui/ApprovalListAdapter.kt
index 7456f16..297f572 100644
--- a/app/src/admin/java/h_mal/appttude/com/driver/ui/ApprovalListAdapter.kt
+++ b/app/src/admin/java/h_mal/appttude/com/driver/ui/ApprovalListAdapter.kt
@@ -1,188 +1,57 @@
package h_mal.appttude.com.driver.ui
-import android.app.Activity
+import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
-import h_mal.appttude.com.driver.admin.objects.wholeObject.MappedObject
-import h_mal.appttude.com.driver.R
+import h_mal.appttude.com.driver.databinding.ApprovalListItemBinding
+import h_mal.appttude.com.driver.model.ApprovalStatus
+import h_mal.appttude.com.driver.utils.hide
+import java.io.IOException
class ApprovalListAdapter(
- private val activity: Activity,
- objects: Array
-) : ArrayAdapter(activity, 0, objects) {
+ private val context: Context,
+ private val data: List>,
+ private val callback: (String) -> Unit
+) : ArrayAdapter>(context, 0, data) {
- var mappedObject: MappedObject? = objects[0]
+ override fun getCount(): Int = data.size
- var names: Array = arrayOf(
- "Driver Profile",
- "Driver License",
- "Private Hire",
- "Vehicle Profile",
- "Insurance",
- "MOT",
- "Logbook",
- "P/H Vehicle"
- )
-
-
- var approvalCode: Int = 0
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
var listItemView: View? = convertView
+ val binding: ApprovalListItemBinding
if (listItemView == null) {
- listItemView = LayoutInflater.from(activity).inflate(
- R.layout.approval_list_grid_item, parent, false
- )
+ // Inflate view binding into listview cell
+ binding = ApprovalListItemBinding.inflate(LayoutInflater.from(context), parent, false)
+ listItemView = binding.root
+ listItemView.setTag(listItemView.id, binding)
+ } else {
+ // cell exists so recycling view
+ binding = listItemView.getTag(listItemView.id) as ApprovalListItemBinding
}
-// approvalCode = getApprovalStatusCode(position)
-// val textView: TextView = listItemView!!.findViewById(R.id.approval_text)
-// textView.text = names.get(position)
-// val imageView: ImageView = listItemView.findViewById(R.id.approval_iv)
-// imageView.setImageResource(
-// MainActivity.approvalsClass!!.setImageResource(
-// approvalCode
-// )
-// )
-// imageView.setOnClickListener {
-// SetApprovalDialog(
-// approvalCode,
-// activity,
-// mappedObject.userId,
-// position,
-// imageView
-// )
-// }
-// val archiveImage: ImageView = listItemView.findViewById(R.id.archive_icon)
-// mappedObject.wholeDriverObject?.archive?.let {
-//
-//
-// archiveImage.visibility = getArchive(
-// position,
-// it
-// )
-// archiveImage.setOnClickListener {
-// var s: String? = null
-// when (position) {
-// 1 -> s = FirebaseClass.DRIVERS_LICENSE_FIREBASE
-// 2 -> s = FirebaseClass.PRIVATE_HIRE_FIREBASE
-// 3 -> s = FirebaseClass.VEHICLE_DETAILS_FIREBASE
-// 4 -> s = FirebaseClass.INSURANCE_FIREBASE
-// 5 -> s = FirebaseClass.MOT_FIREBASE
-// 6 -> s = FirebaseClass.LOG_BOOK_FIREBASE
-// 7 -> s = FirebaseClass.PRIVATE_HIRE_VEHICLE_LICENSE
-// }
-//// executeFragment(ArchiveFragment(), mappedObject.userId, s)
-// }
-// }
-// listItemView.setOnClickListener(View.OnClickListener { getFragment(position) })
-// listItemView.minimumHeight = parent.height / 4
-// listItemView.setPadding(
-// convertDpToPixel(9f, context).toInt(),
-// convertDpToPixel(9f, context).toInt(),
-// convertDpToPixel(9f, context).toInt(),
-// convertDpToPixel(9f, context).toInt()
-// )
- return (listItemView)!!
+
+ val key: String = getItem(position)?.first ?: throw IOException("No document name provided")
+ val approvalStatus: ApprovalStatus? = getItem(position)?.second
+
+ binding.approvalText.text = key
+ approvalStatus?.let { item ->
+ item.score.takeIf { it != 0 }?.let {
+ binding.root.setOnClickListener { callback.invoke(key) }
+ }
+ binding.approvalIv.setImageResource(item.drawableId)
+ binding.approvalStatus.text = context.getString(item.stringId)
+ }
+ // hide divider for first cell
+ if (position == 0) binding.divider.hide()
+
+ return (listItemView)
}
-// override fun getCount(): Int {
-// return 8
-// }
-//
-// private fun getArchive(i: Int, archiveObject: ArchiveObject?): Int {
-// var o: Any? = null
-// val visible: Int
-// when (i) {
-// 0 -> { }
-// 1 -> o = archiveObject!!.driver_license
-// 2 -> o = archiveObject!!.private_hire
-// 3 -> o = archiveObject!!.vehicle_details
-// 4 -> o = archiveObject!!.insurance_details
-// 5 -> o = archiveObject!!.mot_details
-// 6 -> o = archiveObject!!.log_book
-// 7 -> o = archiveObject!!.ph_car
-// }
-// if (o != null) {
-// visible = View.VISIBLE
-// } else {
-// visible = View.GONE
-// }
-// return visible
-// }
-//
-// private fun getFragment(i: Int) {
-// lateinit var f: Fragment
-// val driverProfile by lazy { mappedObject.wholeDriverObject?.driver_profile }
-// val vehicleProfile by lazy { mappedObject.wholeDriverObject?.vehicle_profile }
-// val o: Any? = when (i) {
-// 0 -> {
-// f = DriverProfileFragment()
-// driverProfile?.driver_profile
-// }
-// 1 -> {
-// f = DriverLicenseFragment()
-// driverProfile?.driver_license
-// }
-// 2 -> {
-// f = PrivateHireLicenseFragment()
-// driverProfile?.private_hire
-// }
-// 3 -> {
-// f = VehicleProfileFragment()
-// vehicleProfile?.vehicle_details
-// }
-// 4 -> {
-// f = InsuranceFragment()
-// vehicleProfile?.insurance_details
-// }
-// 5 -> {
-// f = MotFragment()
-// vehicleProfile?.insurance_details
-// }
-// 6 -> {
-// f = LogbookFragment()
-// vehicleProfile?.log_book
-// }
-// 7 -> {
-// f = PrivateHireVehicleFragment()
-// vehicleProfile?.privateHireVehicleObject
-// }
-// else -> null
-// }
-// if (o == null) {
-//// executeFragment(f, mappedObject.userId)
-// } else {
-// MainActivity.archiveClass.openDialogArchive(
-// context, o, mappedObject.userId, f
-// )
-// }
-// }
-//
-// private fun getApprovalStatusCode(i: Int): Int {
-// val statusCode = mappedObject.wholeDriverObject?.approvalsObject?.let{
-// when (i) {
-// 0 -> it.driver_details_approval
-// 1 -> it.driver_license_approval
-// 2 -> it.private_hire_approval
-// 3 -> it.vehicle_details_approval
-// 4 -> it.insurance_details_approval
-// 5 -> it.mot_details_approval
-// 6 -> it.log_book_approval
-// 7 -> it.ph_car_approval
-// else -> FirebaseClass.NO_DATE_PRESENT
-// }
-// }
-// return statusCode ?: FirebaseClass.NO_DATE_PRESENT
-// }
-//
-// companion object {
-// fun convertDpToPixel(dp: Float, context: Context): Float {
-// return dp * (context.resources
-// .displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
-// }
-// }
-
+ fun updateAdapter(date: List>) {
+ clear()
+ addAll(date)
+ }
}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/ui/ApproverFragment.kt b/app/src/admin/java/h_mal/appttude/com/driver/ui/ApproverFragment.kt
new file mode 100644
index 0000000..16df2d8
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/ui/ApproverFragment.kt
@@ -0,0 +1,39 @@
+package h_mal.appttude.com.driver.ui
+
+import h_mal.appttude.com.driver.base.BaseFragment
+import h_mal.appttude.com.driver.databinding.FragmentApproverBinding
+import h_mal.appttude.com.driver.model.ApprovalStatus
+import h_mal.appttude.com.driver.viewmodels.ApproverViewModel
+
+
+class ApproverFragment : BaseFragment() {
+
+ override fun setupView(binding: FragmentApproverBinding) = binding.run {
+ super.setupView(binding)
+
+ val args = requireArguments()
+ viewModel.init(args)
+
+ // Retrieve fragment name argument saved from previous fragment
+ val fragmentClass = viewModel.getFragmentClass()
+
+ childFragmentManager.beginTransaction()
+ .replace(container.id, fragmentClass, args, null)
+ .commitNow()
+
+ approve.setOnClickListener { viewModel.approveDocument() }
+ decline.setOnClickListener { viewModel.declineDocument() }
+ }
+
+ override fun onSuccess(data: Any?) {
+ super.onSuccess(data)
+ when (data) {
+ ApprovalStatus.APPROVED -> displaySnackBar("approved")
+ ApprovalStatus.DENIED -> displaySnackBar("declined")
+ }
+ }
+
+ private fun displaySnackBar(status: String) {
+ showSnackBar("Document has been $status")
+ }
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/ui/DriverOverviewFragment.kt b/app/src/admin/java/h_mal/appttude/com/driver/ui/DriverOverviewFragment.kt
new file mode 100644
index 0000000..3648f15
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/ui/DriverOverviewFragment.kt
@@ -0,0 +1,54 @@
+package h_mal.appttude.com.driver.ui
+
+import android.widget.ListView
+import h_mal.appttude.com.driver.R
+import h_mal.appttude.com.driver.base.BaseFragment
+import h_mal.appttude.com.driver.data.USER_CONST
+import h_mal.appttude.com.driver.databinding.FragmentUserMainBinding
+import h_mal.appttude.com.driver.model.ApprovalStatus
+import h_mal.appttude.com.driver.utils.FRAGMENT
+import h_mal.appttude.com.driver.utils.navigateTo
+import h_mal.appttude.com.driver.utils.toBundle
+import h_mal.appttude.com.driver.viewmodels.DriverOverviewViewModel
+import java.io.IOException
+
+
+class DriverOverviewFragment : BaseFragment() {
+
+ private lateinit var listView: ListView
+ private lateinit var driverId: String
+
+ override fun setupView(binding: FragmentUserMainBinding) {
+ listView = binding.approvalsList
+ loadList()
+ }
+
+ override fun onResume() {
+ super.onResume()
+ loadList()
+ }
+
+ override fun onSuccess(data: Any?) {
+ super.onSuccess(data)
+ @Suppress("UNCHECKED_CAST")
+ if (data is List<*>) {
+ val listData = data as List>
+ if (listView.adapter == null) {
+ listView.adapter = ApprovalListAdapter(requireContext(), listData) {
+ this.view?.navigateTo(
+ R.id.to_approverFragment,
+ driverId.toBundle(USER_CONST).apply { putString(FRAGMENT, it) })
+ }
+ listView.isScrollContainer = false
+ } else {
+ (listView.adapter as ApprovalListAdapter).updateAdapter(listData)
+ }
+ }
+ }
+
+ private fun loadList() {
+ driverId = requireArguments().getString(USER_CONST)
+ ?: throw IOException("No user ID has been passed")
+ viewModel.loadDriverApprovals(driverId)
+ }
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/ui/DriverStatusClass.kt b/app/src/admin/java/h_mal/appttude/com/driver/ui/DriverStatusClass.kt
deleted file mode 100644
index ada9224..0000000
--- a/app/src/admin/java/h_mal/appttude/com/driver/ui/DriverStatusClass.kt
+++ /dev/null
@@ -1,107 +0,0 @@
-package h_mal.appttude.com.driver.ui
-
-import android.app.AlertDialog
-import android.content.Context
-import android.view.View
-import androidx.cardview.widget.CardView
-
-
-class DriverStatusClass : View.OnClickListener {
- var userId: String? = null
- var cardView: CardView? = null
- var context: Context? = null
- var currentSelection: Boolean = false
- override fun onClick(v: View) {
- val choices: Array = arrayOf("Active", "Inactive")
- val alertDialog: AlertDialog.Builder = AlertDialog.Builder(context)
- var selection: Int = -1
- if (currentSelection) {
- selection = 0
- } else if (!currentSelection) {
- selection = 1
- }
- alertDialog.setSingleChoiceItems(
- choices,
- selection
- ) { dialog, which -> }
- alertDialog.create().show()
- }
-
- private fun SetStatus(status: Boolean) {
-// MainActivity.mDatabase!!.child(FirebaseClass.USER_FIREBASE)
-// .child((userId)!!).child(FirebaseClass.DRIVER_STATUS).setValue(status)
-// .addOnCompleteListener { task ->
-// if (task.isSuccessful) {
-// cardView!!.setBackgroundColor(setStatusColour(status))
-// } else {
-// }
-// }
- }
-
- private fun setStatusColour(b: Boolean): Int {
- if (b) {
- return android.R.color.holo_green_dark
- } else {
- return android.R.color.holo_red_dark
- }
- } // public int getOverApprovalStatusCode(WholeDriverObject wholeDriverObject){
- //
- // if (wholeDriverObject.approvalsObject != null){
- // ApprovalsObject approvalsObject = wholeDriverObject.approvalsObject;
- //
- // int[] ints = new int[]{approvalsObject.getDriver_details_approval(),
- // approvalsObject.driver_license_approval,
- // approvalsObject.private_hire_approval,
- // approvalsObject.vehicle_details_approval,
- // approvalsObject.insurance_details_approval,
- // approvalsObject.mot_details_approval,
- // approvalsObject.log_book_approval,
- // approvalsObject.ph_car_approval};
- //
- //
- // return setImageResource(mode(ints));
- // }
- //
- // return setImageResource(NO_DATE_PRESENT);
- // }
- //
- // public void setStatusCode(String userId,String approvalNameString,int status){
- //
- // if (!approvalNameString.equals("")) {
- // mDatabase.child(USER_FIREBASE).child(userId).child(USER_APPROVALS).child(approvalNameString)
- // .setValue(status).addOnCompleteListener(new OnCompleteListener() {
- // @Override
- // public void onComplete(@NonNull Task task) {
- // if (task.isSuccessful()) {
- //
- // } else {
- //
- // }
- // }
- // });
- // }
- //
- //
- // }
- //
- // public int setImageResource(int statusCode){
- // int imageResource;
- //
- // switch (statusCode){
- // case APPROVAL_PENDING:
- // imageResource = R.drawable.pending;
- // break;
- // case APPROVAL_DENIED:
- // imageResource = R.drawable.denied;
- // break;
- // case APPROVED:
- // imageResource = R.drawable.approved;
- // break;
- // default:
- // imageResource = R.drawable.zero;
- // break;
- // }
- //
- // return imageResource;
- // }
-}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/ui/HomeSuperUserFragment.kt b/app/src/admin/java/h_mal/appttude/com/driver/ui/HomeSuperUserFragment.kt
index ea24f2c..7b0e28f 100644
--- a/app/src/admin/java/h_mal/appttude/com/driver/ui/HomeSuperUserFragment.kt
+++ b/app/src/admin/java/h_mal/appttude/com/driver/ui/HomeSuperUserFragment.kt
@@ -1,153 +1,208 @@
package h_mal.appttude.com.driver.ui
import android.app.AlertDialog
-import android.content.DialogInterface
-import android.content.SharedPreferences
import android.os.Bundle
-import android.util.Log
import android.view.*
-import androidx.fragment.app.Fragment
-import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.recyclerview.widget.RecyclerView
+import android.widget.EditText
+import android.widget.LinearLayout
+import androidx.core.view.MenuProvider
+import androidx.core.widget.doOnTextChanged
+import androidx.lifecycle.Lifecycle
+import com.firebase.ui.common.ChangeEventType
+import com.firebase.ui.database.FirebaseRecyclerAdapter
+import com.firebase.ui.database.FirebaseRecyclerOptions
import com.google.firebase.database.DataSnapshot
-import com.google.firebase.database.DatabaseError
-import com.google.firebase.database.DatabaseReference
-import com.google.firebase.database.ValueEventListener
-import h_mal.appttude.com.driver.admin.objects.WholeDriverObject
-import h_mal.appttude.com.driver.admin.objects.wholeObject.MappedObject
import h_mal.appttude.com.driver.R
-import java.io.IOException
+import h_mal.appttude.com.driver.base.BaseFirebaseAdapter
+import h_mal.appttude.com.driver.base.BaseFragment
+import h_mal.appttude.com.driver.base.CustomViewHolder
+import h_mal.appttude.com.driver.data.USER_CONST
+import h_mal.appttude.com.driver.databinding.FragmentHomeSuperUserBinding
+import h_mal.appttude.com.driver.databinding.ListItemLayoutBinding
+import h_mal.appttude.com.driver.model.DatabaseStatus
+import h_mal.appttude.com.driver.model.DatabaseStatus.*
+import h_mal.appttude.com.driver.model.SortOption
+import h_mal.appttude.com.driver.objects.UserObject
+import h_mal.appttude.com.driver.objects.WholeDriverObject
+import h_mal.appttude.com.driver.utils.*
+import h_mal.appttude.com.driver.viewmodels.SuperUserViewModel
import java.util.*
-class HomeSuperUserFragment : Fragment() {
- var users: DatabaseReference? = null
- var mappedObjectList: MutableList? = null
- private var sharedPreferences: SharedPreferences? = null
- private var sortOrder: Int = 0
- private val sortDesc: Boolean = false
- private var recyclerViewAdapter: RecyclerViewAdapter? = null
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setHasOptionsMenu(true)
- mappedObjectList = ArrayList()
- users!!.addValueEventListener(valueEventListener)
- sharedPreferences = requireActivity().getSharedPreferences("PREFS", 0)
+class HomeSuperUserFragment : BaseFragment(),
+ MenuProvider {
+ private lateinit var adapter: FirebaseRecyclerAdapter>
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED)
+ viewModel.retrieveDefaultFirebaseOptions()
}
- override fun onCreateView(
- inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- // Inflate the layout for this fragment
- val view: View = inflater.inflate(R.layout.fragment_home_super_user, container, false)
-
- view.findViewById(R.id.recycler_view).apply {
- layoutManager = LinearLayoutManager(context)
- recyclerViewAdapter = RecyclerViewAdapter(context, mappedObjectList)
- adapter = recyclerViewAdapter
+ override fun onSuccess(data: Any?) {
+ super.onSuccess(data)
+ when (data) {
+ is FirebaseRecyclerOptions<*> -> setAdapterToRecyclerView(data)
+ }
+ }
+ private fun setNonView(status: DatabaseStatus) {
+ applyBinding {
+ emptyView.run {
+ root.setOnClickListener(null)
+ root.visibility = View.VISIBLE
+ icon.setImageResource(status.drawable)
+ header.setText(status.header)
+ subtext.setText(status.subtext)
+ }
}
-
- return view
}
- var valueEventListener: ValueEventListener = object : ValueEventListener {
- override fun onDataChange(snapshot: DataSnapshot) {
- mappedObjectList!!.clear()
- Log.i("Count ", "" + snapshot.childrenCount)
- for (postSnapshot: DataSnapshot in snapshot.children) {
- if ((postSnapshot.child("role").value.toString() == "driver")) {
- mappedObjectList!!.add(
- MappedObject(
- postSnapshot.key, postSnapshot.getValue(
- WholeDriverObject::class.java
- )
+ @Suppress("UNCHECKED_CAST")
+ private fun setAdapterToRecyclerView(options: FirebaseRecyclerOptions<*>) {
+ applyBinding {
+ progressCircular.show()
+ if (recyclerView.adapter == null) {
+ // create an adapter for the first time
+ adapter = createAdapter(options = options as FirebaseRecyclerOptions)
+ recyclerView.adapter = adapter
+ recyclerView.setHasFixedSize(true)
+ adapter.startListening()
+ } else {
+ adapter.updateOptions(options as FirebaseRecyclerOptions)
+ }
+ }
+ }
+
+ override fun onStart() {
+ super.onStart()
+ applyBinding {
+ if (recyclerView.adapter != null) {
+ adapter.startListening()
+ }
+ }
+ }
+
+ override fun onStop() {
+ super.onStop()
+ adapter.stopListening()
+ }
+
+ private fun createAdapter(options: FirebaseRecyclerOptions): BaseFirebaseAdapter {
+ return object :
+ BaseFirebaseAdapter(options, layoutInflater) {
+ override fun onBindViewHolder(
+ holder: CustomViewHolder,
+ position: Int,
+ model: WholeDriverObject
+ ) {
+ val userDetails: UserObject? = model.user_details
+ holder.viewBinding.apply {
+ driverPic.setGlideImage(userDetails?.profilePicString)
+ usernameText.text = userDetails?.profileName
+ emailaddressText.text = userDetails?.profileEmail
+ driverNo.run {
+ val number =
+ if (model.driver_number.isNullOrBlank()) "#N/A" else model.driver_number
+ text = number
+ setOnClickListener {
+ getKeyAtPosition(position)?.let { showChangeNumberDialog(number!!, it) }
+ }
+ }
+ root.setOnClickListener {
+ it.navigateTo(
+ R.id.action_homeAdminFragment_to_userMainFragment,
+ snapshots.getSnapshot(position).key?.toBundle(USER_CONST)
)
- )
+ }
}
}
- sortDate(sortOrder, sortDesc)
- }
-
- override fun onCancelled(databaseError: DatabaseError) {
-
- }
- }
-
- override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
- inflater.inflate(R.menu.menu_calls_fragment, menu)
- super.onCreateOptionsMenu(menu, inflater)
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- if (item.itemId == R.id.archive) {
- val grpname: Array = arrayOf("Driver Name", "Driver Number", "Approval")
- sortOrder = sharedPreferences!!.getInt(SORT, 0)
- val checkedItem: Int = sortOrder
- var compareInt = 0
- val click = DialogInterface.OnClickListener { dialog, _ ->
- sortDate(compareInt, false)
- dialog.dismiss()
- }
- val builder: AlertDialog.Builder = AlertDialog.Builder(context)
- builder.setTitle("Sort by:")
- .setSingleChoiceItems(
- grpname,
- checkedItem
- ) { _, pos -> compareInt = pos }
- .setPositiveButton("Ascending", click)
- .setNegativeButton("Descending", click)
- .create().show()
- }
- return super.onOptionsItemSelected(item)
- }
-
- private fun sortDate(compareInt: Int, reversed: Boolean) {
- val comparator: Comparator = object : Comparator {
- override fun compare(o1: MappedObject, o2: MappedObject): Int {
- when (compareInt) {
- 0 -> return o1.wholeDriverObject?.user_details?.profileName!!.compareTo(
- o2.wholeDriverObject?.user_details?.profileName!!
- )
- 1 -> {
- var s1: String? = o1.wholeDriverObject?.driver_number
- var s2: String? = o2.wholeDriverObject?.driver_number
- if (o1.wholeDriverObject?.driver_number == null || (o1.wholeDriverObject!!
- .driver_number == "0")
- ) {
- s1 = ";"
- }
- if (o2.wholeDriverObject?.driver_number == null || (o2.wholeDriverObject!!
- .driver_number == "0")
- ) {
- s2 = ";"
- }
- return s1!!.compareTo((s2)!!)
- }
- else -> {
- throw IOException("dfdfs")
- }
-// 2 -> return MainActivity.approvalsClass.getOverApprovalStatusCode(o1.wholeDriverObject) -
-// MainActivity.approvalsClass.getOverApprovalStatusCode(o2.wholeDriverObject)
-// else -> return MainActivity.approvalsClass.getOverApprovalStatusCode(
-// o1.wholeDriverObject
-// ) - MainActivity.approvalsClass.getOverApprovalStatusCode(o2.wholeDriverObject)
+ override fun onDataChanged() {
+ super.onDataChanged()
+ applyBinding {
+ // If there are no driver data, show a view that informs the admin.
+ emptyView.root.visibility = if (itemCount == 0) View.VISIBLE else View.GONE
+ progressCircular.hide()
}
}
+
+ override fun onChildChanged(
+ type: ChangeEventType,
+ snapshot: DataSnapshot,
+ newIndex: Int,
+ oldIndex: Int
+ ) {
+ super.onChildChanged(type, snapshot, newIndex, oldIndex)
+ applyBinding { progressCircular.hide() }
+ }
+
+ override fun authorizationError() {
+ setNonView(NO_AUTHORIZATION)
+ }
+
+ override fun cannotRetrieve() {
+ setNonView(CANNOT_RETRIEVE)
+ }
+
+ override fun noConnection() {
+ setNonView(NO_CONNECTION)
+ }
+
+ override fun permissionsDenied() {
+ setNonView(NO_PERMISSION)
+ }
+
+ override fun emptyList() {
+ setNonView(EMPTY_RESULTS)
+ }
}
- sharedPreferences!!.edit().putInt(SORT, compareInt).apply()
- sharedPreferences!!.edit().putBoolean(REVERSED, reversed).apply()
- if (reversed) {
- Collections.sort(mappedObjectList, comparator.reversed())
- } else {
- Collections.sort(mappedObjectList, comparator)
- }
- recyclerViewAdapter!!.notifyDataSetChanged()
}
- companion object {
- private val SORT: String = "SORT"
- private val REVERSED: String = "REVERSED"
+ private fun showChangeNumberDialog(defaultNumber: String, uid: String) {
+ val inputText = EditText(context).apply {
+ setTag(R.string.driver_identifier, "DriverIdentifierInput")
+ setText(defaultNumber)
+ setSelectAllOnFocus(true)
+ doOnTextChanged { _, _, count, _ -> if (count > 6) showToast("Identifier cannot be larger than 6") }
+ }
+ val layout = LinearLayout(context).apply {
+ orientation = LinearLayout.VERTICAL
+ setPadding(28, 0, 56, 0)
+ addView(inputText)
+ }
+
+ AlertDialog.Builder(requireContext(), R.style.AppTheme_AppBarOverlay)
+ .setTitle("Change Driver Identifier")
+ .setView(layout)
+ .setPositiveButton("Submit") { _, _ ->
+ val input = inputText.text?.toString()
+ input?.let { viewModel.updateDriverNumber(uid, it) }
+ }.create().show()
+ }
+
+ override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
+ menuInflater.inflate(R.menu.menu_calls_fragment, menu)
+ }
+
+ override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
+ if (menuItem.itemId == R.id.archive) {
+ displaySortOptions()
+ }
+ return true
+ }
+
+ private fun displaySortOptions() {
+ val groupName: Array = arrayOf("Driver Name", "Driver Number")
+ val defaultPosition = viewModel.getSelectionAsPosition()
+ val builder: AlertDialog.Builder = AlertDialog.Builder(context)
+ builder.setTitle("Sort by:")
+ .setSingleChoiceItems(
+ groupName,
+ defaultPosition
+ ) { _, pos ->
+ val option = SortOption.getSortOptionByLabel(groupName[pos])
+ viewModel.createFirebaseOptions(sort = option)
+ }
+ .create().show()
}
}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/ui/RecyclerViewAdapter.kt b/app/src/admin/java/h_mal/appttude/com/driver/ui/RecyclerViewAdapter.kt
deleted file mode 100644
index e545e4f..0000000
--- a/app/src/admin/java/h_mal/appttude/com/driver/ui/RecyclerViewAdapter.kt
+++ /dev/null
@@ -1,102 +0,0 @@
-package h_mal.appttude.com.driver.ui
-
-import android.app.AlertDialog
-import android.content.Context
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.EditText
-import android.widget.ImageView
-import android.widget.LinearLayout
-import android.widget.TextView
-import androidx.recyclerview.widget.RecyclerView
-import com.squareup.picasso.Picasso
-import h_mal.appttude.com.driver.admin.objects.UserObject
-import h_mal.appttude.com.driver.admin.objects.wholeObject.MappedObject
-import h_mal.appttude.com.driver.R
-
-
-class RecyclerViewAdapter constructor(var context: Context?, var objects: List?) :
- RecyclerView.Adapter() {
- override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): RecyclerView.ViewHolder {
- val viewCurrent: View =
- LayoutInflater.from(context).inflate(R.layout.list_item_layout, viewGroup, false)
- return ViewHolderMain(viewCurrent)
- }
-
- override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, i: Int) {
- val viewHolderCurrent: ViewHolderMain = viewHolder as ViewHolderMain
- val mappedObject: MappedObject = objects!!.get(i)
- val `object`: UserObject? = mappedObject.wholeDriverObject?.user_details
- if (`object`!!.profilePicString != null) {
- Picasso.get()
- .load(`object`.profilePicString)
- .resize(128, 128)
- .placeholder(R.drawable.choice_img_round)
- .into(viewHolderCurrent.profilePicImage)
- } else {
- viewHolderCurrent.profilePicImage.setImageResource(R.drawable.choice_img_round)
- }
- viewHolderCurrent.userNameTextView.setText(`object`.profileName)
- viewHolderCurrent.userEmailTextView.setText(`object`.profileEmail)
- if (mappedObject.wholeDriverObject?.driver_number == null) {
- viewHolderCurrent.driverNo.text = "0"
- } else {
- val s: String = mappedObject.wholeDriverObject?.driver_number.toString()
- viewHolderCurrent.driverNo.text = s
- }
- viewHolderCurrent.driverNo.setOnClickListener {
- val builder: AlertDialog.Builder = AlertDialog.Builder(
- context
- )
- val input: EditText = EditText(context)
- val layout: LinearLayout = LinearLayout(context)
- layout.orientation = LinearLayout.VERTICAL
- layout.setPadding(28, 0, 56, 0)
- input.setText(viewHolderCurrent.driverNo.text.toString())
- input.setSelectAllOnFocus(true)
- layout.addView(input)
- builder.setTitle("Change Driver Number")
- .setView(layout)
- .setPositiveButton(
- "Submit"
- ) { dialog, which ->
-
- }.create()
- .show()
- }
-// viewHolderCurrent.profileApprovalImage.setImageResource(
-// MainActivity.approvalsClass!!.getOverApprovalStatusCode(mappedObject.wholeDriverObject)
-// )
- viewHolderCurrent.itemView.setOnClickListener {
- val bundle: Bundle = Bundle()
- bundle.putParcelable("mapped", mappedObject)
-// executeFragment(UserMainFragment(), bundle)
- }
- }
-
- override fun getItemCount(): Int {
- return objects!!.size
- }
-
- internal inner class ViewHolderMain constructor(listItemView: View) :
- RecyclerView.ViewHolder(listItemView) {
- var profilePicImage: ImageView
- var userNameTextView: TextView
- var userEmailTextView: TextView
-
- // CardView statusCard;
- var profileApprovalImage: ImageView
- var driverNo: TextView
-
- init {
- profilePicImage = listItemView.findViewById(R.id.driverPic)
- userNameTextView = listItemView.findViewById(R.id.username_text)
- // statusCard = listItemView.findViewById(R.id.status_icon);
- userEmailTextView = listItemView.findViewById(R.id.emailaddress_text)
- profileApprovalImage = listItemView.findViewById(R.id.approval_iv)
- driverNo = listItemView.findViewById(R.id.driver_no)
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/ui/UserMainFragment.kt b/app/src/admin/java/h_mal/appttude/com/driver/ui/UserMainFragment.kt
deleted file mode 100644
index ada4bdd..0000000
--- a/app/src/admin/java/h_mal/appttude/com/driver/ui/UserMainFragment.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-package h_mal.appttude.com.driver.ui
-
-import android.os.Bundle
-import android.util.Log
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.GridView
-import androidx.fragment.app.Fragment
-import h_mal.appttude.com.driver.admin.objects.wholeObject.MappedObject
-import h_mal.appttude.com.driver.R
-
-
-class UserMainFragment : Fragment() {
-
- override fun onCreateView(
- inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- // Inflate the layout for this fragment
- val view: View = inflater.inflate(R.layout.fragment_user_main, container, false)
- Log.i("UserMain", "onCreateView: height = " + view.height)
- val mappedObject: MappedObject? = requireArguments().getParcelable("mapped")
- activity?.title = mappedObject?.wholeDriverObject?.user_details?.profileName
-
- val listView: GridView = view.findViewById(R.id.approvals_list)
- listView.adapter = ApprovalListAdapter(requireActivity(), arrayOf(mappedObject))
- return view
- }
-}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/ui/driverprofile/DriverLicenseFragment.kt b/app/src/admin/java/h_mal/appttude/com/driver/ui/driverprofile/DriverLicenseFragment.kt
new file mode 100644
index 0000000..de8542a
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/ui/driverprofile/DriverLicenseFragment.kt
@@ -0,0 +1,26 @@
+package h_mal.appttude.com.driver.ui.driverprofile
+
+import h_mal.appttude.com.driver.base.DataViewerFragment
+import h_mal.appttude.com.driver.databinding.FragmentDriverLicenseBinding
+import h_mal.appttude.com.driver.model.DriversLicense
+import h_mal.appttude.com.driver.utils.setGlideImage
+import h_mal.appttude.com.driver.viewmodels.DriverLicenseViewModel
+
+class DriverLicenseFragment :
+ DataViewerFragment() {
+
+ override fun setupView(binding: FragmentDriverLicenseBinding) {
+ super.setupView(binding)
+ viewsToHide(binding.submit, binding.searchImage)
+ }
+
+ override fun setFields(data: DriversLicense) {
+ super.setFields(data)
+ applyBinding {
+ driversliImg.setGlideImage(data.licenseImageString)
+ licNo.setText(data.licenseNumber)
+ licExpiry.setText(data.licenseExpiry)
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/ui/driverprofile/DriverProfileFragment.kt b/app/src/admin/java/h_mal/appttude/com/driver/ui/driverprofile/DriverProfileFragment.kt
new file mode 100644
index 0000000..2dc8b81
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/ui/driverprofile/DriverProfileFragment.kt
@@ -0,0 +1,31 @@
+package h_mal.appttude.com.driver.ui.driverprofile
+
+import h_mal.appttude.com.driver.base.DataViewerFragment
+import h_mal.appttude.com.driver.databinding.FragmentDriverProfileBinding
+import h_mal.appttude.com.driver.model.DriverProfile
+import h_mal.appttude.com.driver.utils.setGlideImage
+import h_mal.appttude.com.driver.viewmodels.DriverProfileViewModel
+
+
+class DriverProfileFragment :
+ DataViewerFragment() {
+
+ override fun setupView(binding: FragmentDriverProfileBinding) {
+ super.setupView(binding)
+ viewsToHide(binding.submit, binding.addPhoto)
+ }
+
+ override fun setFields(data: DriverProfile) {
+ super.setFields(data)
+ applyBinding {
+ driverPic.setGlideImage(data.driverPic)
+ namesInput.setText(data.forenames)
+ addressInput.setText(data.address)
+ postcodeInput.setText(data.postcode)
+ dobInput.setText(data.dob)
+ niNumber.setText(data.ni)
+ dateFirst.setText(data.dateFirst)
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/ui/driverprofile/PrivateHireLicenseFragment.kt b/app/src/admin/java/h_mal/appttude/com/driver/ui/driverprofile/PrivateHireLicenseFragment.kt
new file mode 100644
index 0000000..8fce996
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/ui/driverprofile/PrivateHireLicenseFragment.kt
@@ -0,0 +1,26 @@
+package h_mal.appttude.com.driver.ui.driverprofile
+
+import h_mal.appttude.com.driver.base.DataViewerFragment
+import h_mal.appttude.com.driver.databinding.FragmentPrivateHireLicenseBinding
+import h_mal.appttude.com.driver.model.PrivateHireLicense
+import h_mal.appttude.com.driver.utils.setGlideImage
+import h_mal.appttude.com.driver.viewmodels.PrivateHireLicenseViewModel
+
+
+class PrivateHireLicenseFragment : DataViewerFragment() {
+
+ override fun setupView(binding: FragmentPrivateHireLicenseBinding) {
+ super.setupView(binding)
+ viewsToHide(binding.submit, binding.uploadphlic)
+ }
+
+ override fun setFields(data: PrivateHireLicense) {
+ super.setFields(data)
+ applyBinding {
+ imageView2.setGlideImage(data.phImageString)
+ phNo.setText(data.phNumber)
+ phExpiry.setText(data.phExpiry)
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/ui/vehicleprofile/InsuranceFragment.kt b/app/src/admin/java/h_mal/appttude/com/driver/ui/vehicleprofile/InsuranceFragment.kt
new file mode 100644
index 0000000..12cf1f4
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/ui/vehicleprofile/InsuranceFragment.kt
@@ -0,0 +1,45 @@
+package h_mal.appttude.com.driver.ui.vehicleprofile
+
+import android.net.Uri
+import android.widget.ImageView
+import h_mal.appttude.com.driver.base.DataViewerFragment
+import h_mal.appttude.com.driver.databinding.FragmentInsuranceBinding
+import h_mal.appttude.com.driver.model.Insurance
+import h_mal.appttude.com.driver.utils.setGlideImage
+import h_mal.appttude.com.driver.viewmodels.InsuranceViewModel
+
+
+class InsuranceFragment :
+ DataViewerFragment() {
+
+ override fun setupView(binding: FragmentInsuranceBinding) {
+ super.setupView(binding)
+ viewsToHide(binding.submit, binding.uploadInsurance)
+ }
+
+
+ private fun updateImageCarousal(list: List) {
+ applyBinding {
+ carouselView.setImageClickListener(null)
+ carouselView.setImageListener { i: Int, imageView: ImageView ->
+ when (list[i]) {
+ is Uri -> {
+ imageView.setGlideImage(list[i] as Uri)
+ }
+ is String -> imageView.setGlideImage(list[i] as String)
+ }
+ }
+ carouselView.pageCount = list.size
+ }
+ }
+
+ override fun setFields(data: Insurance) {
+ super.setFields(data)
+ applyBinding {
+ insurer.setText(data.insurerName)
+ insuranceExp.setText(data.expiryDate)
+ data.photoStrings?.let { updateImageCarousal(it) }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/ui/vehicleprofile/LogbookFragment.kt b/app/src/admin/java/h_mal/appttude/com/driver/ui/vehicleprofile/LogbookFragment.kt
new file mode 100644
index 0000000..679ddb9
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/ui/vehicleprofile/LogbookFragment.kt
@@ -0,0 +1,26 @@
+package h_mal.appttude.com.driver.ui.vehicleprofile
+
+import h_mal.appttude.com.driver.base.DataViewerFragment
+import h_mal.appttude.com.driver.databinding.FragmentLogbookBinding
+import h_mal.appttude.com.driver.model.Logbook
+import h_mal.appttude.com.driver.utils.setGlideImage
+import h_mal.appttude.com.driver.viewmodels.LogbookViewModel
+
+
+class LogbookFragment :
+ DataViewerFragment() {
+
+ override fun setupView(binding: FragmentLogbookBinding) {
+ super.setupView(binding)
+ viewsToHide(binding.submit, binding.uploadLb)
+ }
+
+ override fun setFields(data: Logbook) {
+ super.setFields(data)
+ applyBinding {
+ logBookImg.setGlideImage(data.photoString)
+ v5cNo.setText(data.v5cnumber)
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/ui/vehicleprofile/MotFragment.kt b/app/src/admin/java/h_mal/appttude/com/driver/ui/vehicleprofile/MotFragment.kt
new file mode 100644
index 0000000..1c0a744
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/ui/vehicleprofile/MotFragment.kt
@@ -0,0 +1,25 @@
+package h_mal.appttude.com.driver.ui.vehicleprofile
+
+import h_mal.appttude.com.driver.base.DataViewerFragment
+import h_mal.appttude.com.driver.databinding.FragmentMotBinding
+import h_mal.appttude.com.driver.model.Mot
+import h_mal.appttude.com.driver.utils.setGlideImage
+import h_mal.appttude.com.driver.viewmodels.MotViewModel
+
+
+class MotFragment : DataViewerFragment() {
+
+ override fun setupView(binding: FragmentMotBinding) {
+ super.setupView(binding)
+ viewsToHide(binding.submit, binding.uploadmot)
+ }
+
+ override fun setFields(data: Mot) {
+ super.setFields(data)
+ applyBinding {
+ motImg.setGlideImage(data.motImageString)
+ motExpiry.setText(data.motExpiry)
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/ui/vehicleprofile/PrivateHireVehicleFragment.kt b/app/src/admin/java/h_mal/appttude/com/driver/ui/vehicleprofile/PrivateHireVehicleFragment.kt
new file mode 100644
index 0000000..b64e84d
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/ui/vehicleprofile/PrivateHireVehicleFragment.kt
@@ -0,0 +1,28 @@
+package h_mal.appttude.com.driver.ui.vehicleprofile
+
+import h_mal.appttude.com.driver.base.DataViewerFragment
+import h_mal.appttude.com.driver.databinding.FragmentPrivateHireLicenseBinding
+import h_mal.appttude.com.driver.model.PrivateHireVehicle
+import h_mal.appttude.com.driver.utils.setGlideImage
+import h_mal.appttude.com.driver.viewmodels.PrivateHireVehicleViewModel
+
+
+class PrivateHireVehicleFragment :
+ DataViewerFragment() {
+
+ override fun setupView(binding: FragmentPrivateHireLicenseBinding) {
+ super.setupView(binding)
+ viewsToHide(binding.submit, binding.uploadphlic)
+ }
+
+ override fun setFields(data: PrivateHireVehicle) {
+ super.setFields(data)
+ applyBinding {
+ imageView2.setGlideImage(data.phCarImageString)
+ phNo.setText(data.phCarNumber)
+ phExpiry.setText(data.phCarExpiry)
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/ui/vehicleprofile/VehicleProfileFragment.kt b/app/src/admin/java/h_mal/appttude/com/driver/ui/vehicleprofile/VehicleProfileFragment.kt
new file mode 100644
index 0000000..309cab7
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/ui/vehicleprofile/VehicleProfileFragment.kt
@@ -0,0 +1,32 @@
+package h_mal.appttude.com.driver.ui.vehicleprofile
+
+import h_mal.appttude.com.driver.base.DataViewerFragment
+import h_mal.appttude.com.driver.databinding.FragmentVehicleSetupBinding
+import h_mal.appttude.com.driver.model.VehicleProfile
+import h_mal.appttude.com.driver.viewmodels.VehicleProfileViewModel
+
+
+class VehicleProfileFragment :
+ DataViewerFragment() {
+
+ override fun setupView(binding: FragmentVehicleSetupBinding) {
+ super.setupView(binding)
+ viewsToHide(binding.submit)
+ binding.seizedCheckbox.isEnabled = false
+ }
+
+ override fun setFields(data: VehicleProfile) {
+ super.setFields(data)
+ applyBinding {
+ reg.setText(data.reg)
+ make.setText(data.make)
+ carModel.setText(data.model)
+ colour.setText(data.colour)
+ keeperName.setText(data.keeperName)
+ address.setText(data.keeperAddress)
+ postcode.setText(data.keeperPostCode)
+ startDate.setText(data.startDate)
+ seizedCheckbox.isChecked = data.isSeized
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/utils/Constants.kt b/app/src/admin/java/h_mal/appttude/com/driver/utils/Constants.kt
new file mode 100644
index 0000000..09d4953
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/utils/Constants.kt
@@ -0,0 +1,3 @@
+package h_mal.appttude.com.driver.utils
+
+const val FRAGMENT = "fragment"
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/ApproverViewModel.kt b/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/ApproverViewModel.kt
new file mode 100644
index 0000000..d31570b
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/ApproverViewModel.kt
@@ -0,0 +1,104 @@
+package h_mal.appttude.com.driver.viewmodels
+
+import android.content.res.Resources
+import android.os.Bundle
+import androidx.fragment.app.Fragment
+import com.google.firebase.database.DatabaseReference
+import h_mal.appttude.com.driver.R
+import h_mal.appttude.com.driver.base.BaseViewModel
+import h_mal.appttude.com.driver.data.FirebaseCompletion
+import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
+import h_mal.appttude.com.driver.data.USER_CONST
+import h_mal.appttude.com.driver.model.ApprovalStatus
+import h_mal.appttude.com.driver.objects.ApprovalsObject
+import h_mal.appttude.com.driver.ui.driverprofile.DriverLicenseFragment
+import h_mal.appttude.com.driver.ui.driverprofile.DriverProfileFragment
+import h_mal.appttude.com.driver.ui.driverprofile.PrivateHireLicenseFragment
+import h_mal.appttude.com.driver.ui.vehicleprofile.InsuranceFragment
+import h_mal.appttude.com.driver.ui.vehicleprofile.LogbookFragment
+import h_mal.appttude.com.driver.ui.vehicleprofile.MotFragment
+import h_mal.appttude.com.driver.ui.vehicleprofile.PrivateHireVehicleFragment
+import h_mal.appttude.com.driver.ui.vehicleprofile.VehicleProfileFragment
+import h_mal.appttude.com.driver.utils.Coroutines.io
+import h_mal.appttude.com.driver.utils.FRAGMENT
+import h_mal.appttude.com.driver.utils.getDataFromDatabaseRef
+
+class ApproverViewModel(
+ private val resources: Resources,
+ private val database: FirebaseDatabaseSource
+) : BaseViewModel() {
+
+ private lateinit var name: String
+ private lateinit var docRef: DatabaseReference
+
+ private var score: ApprovalStatus? = null
+
+ fun init(args: Bundle) {
+ // Retried uid & fragment class name from args
+ val uid = args.getString(USER_CONST) ?: throw NullPointerException("No user Id was passed")
+ name = args.getString(FRAGMENT)
+ ?: throw NullPointerException("No fragment name argument passed")
+ // Define a document name based on fragment class name
+ val documentName = when (name) {
+ resources.getString(R.string.driver_profile) -> ApprovalsObject::driver_details_approval.name
+ resources.getString(R.string.drivers_license) -> ApprovalsObject::driver_license_approval.name
+ resources.getString(R.string.private_hire_license) -> ApprovalsObject::private_hire_approval.name
+ resources.getString(R.string.vehicle_profile) -> ApprovalsObject::vehicle_details_approval.name
+ resources.getString(R.string.insurance) -> ApprovalsObject::insurance_details_approval.name
+ resources.getString(R.string.m_o_t) -> ApprovalsObject::mot_details_approval.name
+ resources.getString(R.string.log_book) -> ApprovalsObject::log_book_approval.name
+ resources.getString(R.string.private_hire_vehicle_license) -> ApprovalsObject::ph_car_approval.name
+ else -> {
+ throw StringIndexOutOfBoundsException("No resource for $name")
+ }
+ }
+
+ docRef = database.getDocumentApprovalRef(uid, documentName)
+ io {
+ doTryOperation("") {
+ val data = docRef.getDataFromDatabaseRef()
+ score = data?.let { ApprovalStatus.getByScore(it) } ?: ApprovalStatus.NOT_SUBMITTED
+ onSuccess(FirebaseCompletion.Default)
+ }
+ }
+ }
+
+ fun getFragmentClass(): Class {
+ return when (name) {
+ resources.getString(R.string.driver_profile) -> DriverProfileFragment::class.java
+ resources.getString(R.string.drivers_license) -> DriverLicenseFragment::class.java
+ resources.getString(R.string.private_hire_license) -> PrivateHireLicenseFragment::class.java
+ resources.getString(R.string.vehicle_profile) -> VehicleProfileFragment::class.java
+ resources.getString(R.string.insurance) -> InsuranceFragment::class.java
+ resources.getString(R.string.m_o_t) -> MotFragment::class.java
+ resources.getString(R.string.log_book) -> LogbookFragment::class.java
+ resources.getString(R.string.private_hire_vehicle_license) -> PrivateHireVehicleFragment::class.java
+ else -> {
+ throw StringIndexOutOfBoundsException("No resource for $name")
+ }
+ }
+ }
+
+ fun approveDocument() {
+ updateDocument(ApprovalStatus.APPROVED)
+ }
+
+ fun declineDocument() {
+ updateDocument(ApprovalStatus.DENIED)
+ }
+
+ private fun updateDocument(approval: ApprovalStatus) {
+ if (approval == score) {
+ val result = if (approval == ApprovalStatus.APPROVED) "approved" else "declined"
+ onError("Document already $result")
+ return
+ }
+
+ io {
+ doTryOperation("Failed to decline document") {
+ database.postToDatabaseRed(docRef, approval.score)
+ onSuccess(approval)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/DriverLicenseViewModel.kt b/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/DriverLicenseViewModel.kt
new file mode 100644
index 0000000..86725a8
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/DriverLicenseViewModel.kt
@@ -0,0 +1,12 @@
+package h_mal.appttude.com.driver.viewmodels
+
+import h_mal.appttude.com.driver.base.DataViewerBaseViewModel
+import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
+import h_mal.appttude.com.driver.model.DriversLicense
+
+class DriverLicenseViewModel(
+ private val database: FirebaseDatabaseSource
+) : DataViewerBaseViewModel() {
+
+ override fun getDatabaseRef(uid: String) = database.getDriverLicenseRef(uid)
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/DriverOverviewViewModel.kt b/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/DriverOverviewViewModel.kt
new file mode 100644
index 0000000..fbda4ad
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/DriverOverviewViewModel.kt
@@ -0,0 +1,61 @@
+package h_mal.appttude.com.driver.viewmodels
+
+import com.google.firebase.database.DatabaseReference
+import com.google.firebase.storage.StorageReference
+import h_mal.appttude.com.driver.base.DataSubmissionBaseViewModel
+import h_mal.appttude.com.driver.data.FirebaseAuthentication
+import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
+import h_mal.appttude.com.driver.model.ApprovalStatus
+import h_mal.appttude.com.driver.objects.ApprovalsObject
+import h_mal.appttude.com.driver.utils.Coroutines.io
+import h_mal.appttude.com.driver.utils.getDataFromDatabaseRef
+import kotlinx.coroutines.Job
+import java.io.IOException
+
+class DriverOverviewViewModel(
+ auth: FirebaseAuthentication,
+ private val database: FirebaseDatabaseSource
+) : DataSubmissionBaseViewModel(auth, database, null) {
+
+ private var driverId: String? = null
+
+ override val databaseRef: DatabaseReference = database.getApprovalsRef(driverId ?: "")
+ override val storageRef: StorageReference? = null
+ override val objectName: String = "Approvals"
+
+ override fun getDataFromDatabase(): Job = retrieveDataFromDatabase()
+
+ fun loadDriverApprovals(driverId: String?) {
+ this.driverId = driverId
+ io {
+ doTryOperation("Failed to retrieve $objectName") {
+ val data = driverId?.let {
+ database.getApprovalsRef(it).getDataFromDatabaseRef()
+ } ?: ApprovalsObject()
+ val mappedData = mapApprovalsForView(data)
+ onSuccess(mappedData)
+ return@doTryOperation
+ }
+ }
+ }
+
+ private fun mapApprovalsForView(data: ApprovalsObject): List> {
+ val list = mutableListOf>()
+ return list.apply {
+ add(0, Pair("Driver Profile", getApprovalStatusByScore(data.driver_details_approval)))
+ add(1, Pair("Drivers License", getApprovalStatusByScore(data.driver_license_approval)))
+ add(2, Pair("Private Hire License", getApprovalStatusByScore(data.private_hire_approval)))
+ add(3, Pair("Vehicle Profile", getApprovalStatusByScore(data.vehicle_details_approval)))
+ add(4, Pair("Insurance", getApprovalStatusByScore(data.insurance_details_approval)))
+ add(5, Pair("M.O.T", getApprovalStatusByScore(data.mot_details_approval)))
+ add(6, Pair("Log book", getApprovalStatusByScore(data.log_book_approval)))
+ add(7, Pair("Private Hire Vehicle License", getApprovalStatusByScore(data.ph_car_approval)))
+ }
+ }
+
+ private fun getApprovalStatusByScore(score: Int): ApprovalStatus {
+ if (score == 0) return ApprovalStatus.NOT_SUBMITTED
+ return ApprovalStatus.getByScore(score) ?: throw IOException("No approval for score $score")
+ }
+
+}
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/DriverProfileViewModel.kt b/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/DriverProfileViewModel.kt
new file mode 100644
index 0000000..4b0c6c4
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/DriverProfileViewModel.kt
@@ -0,0 +1,11 @@
+package h_mal.appttude.com.driver.viewmodels
+
+import h_mal.appttude.com.driver.base.DataViewerBaseViewModel
+import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
+import h_mal.appttude.com.driver.model.DriverProfile
+
+class DriverProfileViewModel(
+ private val database: FirebaseDatabaseSource
+) : DataViewerBaseViewModel() {
+ override fun getDatabaseRef(uid: String) = database.getDriverDetailsRef(uid)
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/InsuranceViewModel.kt b/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/InsuranceViewModel.kt
new file mode 100644
index 0000000..6aed36d
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/InsuranceViewModel.kt
@@ -0,0 +1,12 @@
+package h_mal.appttude.com.driver.viewmodels
+
+import h_mal.appttude.com.driver.base.DataViewerBaseViewModel
+import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
+import h_mal.appttude.com.driver.model.Insurance
+
+class InsuranceViewModel(
+ private val database: FirebaseDatabaseSource
+) : DataViewerBaseViewModel() {
+
+ override fun getDatabaseRef(uid: String) = database.getInsuranceDetailsRef(uid)
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/LogbookViewModel.kt b/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/LogbookViewModel.kt
new file mode 100644
index 0000000..2bad2c1
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/LogbookViewModel.kt
@@ -0,0 +1,12 @@
+package h_mal.appttude.com.driver.viewmodels
+
+import h_mal.appttude.com.driver.base.DataViewerBaseViewModel
+import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
+import h_mal.appttude.com.driver.model.Logbook
+
+class LogbookViewModel(
+ private val database: FirebaseDatabaseSource
+) : DataViewerBaseViewModel() {
+
+ override fun getDatabaseRef(uid: String) = database.getLogbookRef(uid)
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/MotViewModel.kt b/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/MotViewModel.kt
new file mode 100644
index 0000000..3143066
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/MotViewModel.kt
@@ -0,0 +1,12 @@
+package h_mal.appttude.com.driver.viewmodels
+
+import h_mal.appttude.com.driver.base.DataViewerBaseViewModel
+import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
+import h_mal.appttude.com.driver.model.Mot
+
+class MotViewModel(
+ private val database: FirebaseDatabaseSource
+) : DataViewerBaseViewModel() {
+
+ override fun getDatabaseRef(uid: String) = database.getMotDetailsRef(uid)
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/PrivateHireLicenseViewModel.kt b/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/PrivateHireLicenseViewModel.kt
new file mode 100644
index 0000000..73cc556
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/PrivateHireLicenseViewModel.kt
@@ -0,0 +1,12 @@
+package h_mal.appttude.com.driver.viewmodels
+
+import h_mal.appttude.com.driver.base.DataViewerBaseViewModel
+import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
+import h_mal.appttude.com.driver.model.PrivateHireLicense
+
+class PrivateHireLicenseViewModel(
+ private val database: FirebaseDatabaseSource
+) : DataViewerBaseViewModel() {
+
+ override fun getDatabaseRef(uid: String) = database.getPrivateHireRef(uid)
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/PrivateHireVehicleViewModel.kt b/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/PrivateHireVehicleViewModel.kt
new file mode 100644
index 0000000..1716d75
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/PrivateHireVehicleViewModel.kt
@@ -0,0 +1,12 @@
+package h_mal.appttude.com.driver.viewmodels
+
+import h_mal.appttude.com.driver.base.DataViewerBaseViewModel
+import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
+import h_mal.appttude.com.driver.model.PrivateHireVehicle
+
+class PrivateHireVehicleViewModel(
+ private val database: FirebaseDatabaseSource
+) : DataViewerBaseViewModel() {
+
+ override fun getDatabaseRef(uid: String) = database.getPrivateHireVehicleRef(uid)
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/SuperUserViewModel.kt b/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/SuperUserViewModel.kt
new file mode 100644
index 0000000..9fdda57
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/SuperUserViewModel.kt
@@ -0,0 +1,65 @@
+package h_mal.appttude.com.driver.viewmodels
+
+import com.firebase.ui.database.FirebaseRecyclerOptions
+import h_mal.appttude.com.driver.base.BaseViewModel
+import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
+import h_mal.appttude.com.driver.data.prefs.PreferenceProvider
+import h_mal.appttude.com.driver.model.SortOption
+import h_mal.appttude.com.driver.objects.WholeDriverObject
+import h_mal.appttude.com.driver.utils.Coroutines.io
+import h_mal.appttude.com.driver.utils.isNotNull
+
+
+class SuperUserViewModel(
+ private val firebaseDatabaseSource: FirebaseDatabaseSource,
+ private val preferenceProvider: PreferenceProvider
+) : BaseViewModel() {
+
+ fun retrieveDefaultFirebaseOptions() {
+ val optionLabel = preferenceProvider.getSortOption()
+ val option = SortOption.getSortOptionByLabel(optionLabel)
+ createFirebaseOptions(option)
+ }
+
+ fun createFirebaseOptions(sort: SortOption? = null) {
+ val ref = firebaseDatabaseSource.getUsersRef().orderByChild("role").startAt("driver").endAt("driver")
+
+ sort?.isNotNull { preferenceProvider.setSortOption(it.label) }
+
+// val query = when(sort) {
+// NAME, NUMBER -> ref.orderByChild(sort.key)
+//// SortOption.APPROVAL -> TODO()
+// else -> ref.orderByKey()
+// }
+
+ val options = FirebaseRecyclerOptions.Builder()
+ .setQuery(ref, WholeDriverObject::class.java)
+ .build()
+
+ onSuccess(options)
+ }
+
+ fun updateDriverNumber(uid: String, input: String?) {
+ io {
+ doTryOperation("failed update driver identifier") {
+ // validate input
+ if (input.isNullOrBlank()) {
+ onError("No driver identifier provided")
+ return@doTryOperation
+ }
+ val text = if (input.length > 6) input.substring(0, 7) else input
+
+ firebaseDatabaseSource.run {
+ postToDatabaseRed(getDriverNumberRef(uid), text)
+ onSuccess(Unit)
+ }
+ }
+ }
+ }
+
+ fun getSelectionAsPosition(): Int {
+ val optionLabel = preferenceProvider.getSortOption()
+ return SortOption.getPositionByLabel(optionLabel) ?: -1
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/VehicleProfileViewModel.kt b/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/VehicleProfileViewModel.kt
new file mode 100644
index 0000000..ca13476
--- /dev/null
+++ b/app/src/admin/java/h_mal/appttude/com/driver/viewmodels/VehicleProfileViewModel.kt
@@ -0,0 +1,12 @@
+package h_mal.appttude.com.driver.viewmodels
+
+import h_mal.appttude.com.driver.base.DataViewerBaseViewModel
+import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
+import h_mal.appttude.com.driver.model.VehicleProfile
+
+class VehicleProfileViewModel(
+ private val database: FirebaseDatabaseSource
+) : DataViewerBaseViewModel() {
+
+ override fun getDatabaseRef(uid: String) = database.getVehicleDetailsRef(uid)
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/admin/res/layout/activity_main.xml
similarity index 100%
rename from app/src/main/res/layout/activity_main.xml
rename to app/src/admin/res/layout/activity_main.xml
diff --git a/app/src/admin/res/layout/approval_list_grid_item.xml b/app/src/admin/res/layout/approval_list_grid_item.xml
deleted file mode 100644
index 3eef1e4..0000000
--- a/app/src/admin/res/layout/approval_list_grid_item.xml
+++ /dev/null
@@ -1,93 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/admin/res/layout/approval_list_item.xml b/app/src/admin/res/layout/approval_list_item.xml
new file mode 100644
index 0000000..9b9be7e
--- /dev/null
+++ b/app/src/admin/res/layout/approval_list_item.xml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/admin/res/layout/empty_layout.xml b/app/src/admin/res/layout/empty_layout.xml
new file mode 100644
index 0000000..7894b2e
--- /dev/null
+++ b/app/src/admin/res/layout/empty_layout.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/admin/res/layout/empty_users_view.xml b/app/src/admin/res/layout/empty_users_view.xml
new file mode 100644
index 0000000..d830efc
--- /dev/null
+++ b/app/src/admin/res/layout/empty_users_view.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/admin/res/layout/fragment_approver.xml b/app/src/admin/res/layout/fragment_approver.xml
new file mode 100644
index 0000000..71d5ae4
--- /dev/null
+++ b/app/src/admin/res/layout/fragment_approver.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/admin/res/layout/fragment_home_super_user.xml b/app/src/admin/res/layout/fragment_home_super_user.xml
index dcf94cf..9a8e8a7 100644
--- a/app/src/admin/res/layout/fragment_home_super_user.xml
+++ b/app/src/admin/res/layout/fragment_home_super_user.xml
@@ -1,16 +1,42 @@
-
-
-
\ No newline at end of file
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/admin/res/layout/fragment_user_main.xml b/app/src/admin/res/layout/fragment_user_main.xml
index c2ea597..c7cb829 100644
--- a/app/src/admin/res/layout/fragment_user_main.xml
+++ b/app/src/admin/res/layout/fragment_user_main.xml
@@ -1,17 +1,32 @@
-
+ tools:context=".ui.DriverOverviewFragment">
-
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_marginBottom="12dp"
+ app:cardBackgroundColor="@color/colour_nine"
+ app:cardCornerRadius="28dp"
+ app:cardElevation="0dp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="parent">
-
\ No newline at end of file
+
+
+
+
\ No newline at end of file
diff --git a/app/src/admin/res/layout/list_item_layout.xml b/app/src/admin/res/layout/list_item_layout.xml
index c7446e5..7f935f3 100644
--- a/app/src/admin/res/layout/list_item_layout.xml
+++ b/app/src/admin/res/layout/list_item_layout.xml
@@ -10,7 +10,7 @@
android:id="@+id/driverPic"
android:layout_width="50dp"
android:layout_height="50dp"
- android:layout_marginLeft="24dp"
+ android:layout_marginStart="24dp"
android:layout_marginTop="24dp"
android:layout_marginBottom="24dp"
android:adjustViewBounds="true"
@@ -26,18 +26,19 @@
android:id="@+id/approval_iv"
android:layout_width="10dp"
android:layout_height="10dp"
- android:layout_marginRight="3dp"
+ android:layout_marginEnd="3dp"
android:layout_marginTop="3dp"
app:layout_constraintTop_toTopOf="@id/driverPic"
app:layout_constraintRight_toRightOf="@id/driverPic"
android:adjustViewBounds="true"
- tools:src="@android:drawable/presence_online" />
+ tools:src="@android:drawable/presence_online"
+ android:contentDescription="@string/user_status" />
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/admin/res/values/strings.xml b/app/src/admin/res/values/strings.xml
new file mode 100644
index 0000000..dbfce83
--- /dev/null
+++ b/app/src/admin/res/values/strings.xml
@@ -0,0 +1,5 @@
+
+ Driver Admin
+
+ Hello blank fragment
+
\ No newline at end of file
diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/BaseTestRobot.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/BaseTestRobot.kt
index 0da5e65..bf99b98 100644
--- a/app/src/androidTest/java/h_mal/appttude/com/driver/BaseTestRobot.kt
+++ b/app/src/androidTest/java/h_mal/appttude/com/driver/BaseTestRobot.kt
@@ -1,17 +1,44 @@
package h_mal.appttude.com.driver
+import android.app.Activity
+import android.app.Instrumentation
+import android.content.Intent
import android.content.res.Resources
+import android.net.Uri
+import android.view.View
+import android.widget.DatePicker
+import android.widget.ListView
import androidx.annotation.StringRes
+import androidx.recyclerview.widget.RecyclerView.ViewHolder
import androidx.test.espresso.Espresso.onData
import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.UiController
+import androidx.test.espresso.ViewAction
import androidx.test.espresso.ViewInteraction
import androidx.test.espresso.action.ViewActions
+import androidx.test.espresso.action.ViewActions.click
+import androidx.test.espresso.action.ViewActions.swipeDown
import androidx.test.espresso.assertion.ViewAssertions.matches
-import androidx.test.espresso.matcher.ViewMatchers
+import androidx.test.espresso.contrib.PickerActions
+import androidx.test.espresso.contrib.RecyclerViewActions
+import androidx.test.espresso.intent.Intents
+import androidx.test.espresso.intent.Intents.intending
+import androidx.test.espresso.intent.matcher.IntentMatchers
+import androidx.test.espresso.intent.matcher.IntentMatchers.hasAction
+import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
+import androidx.test.espresso.matcher.ViewMatchers.isRoot
+import androidx.test.espresso.matcher.ViewMatchers.withClassName
import androidx.test.espresso.matcher.ViewMatchers.withId
+import androidx.test.espresso.matcher.ViewMatchers.withText
+import h_mal.appttude.com.driver.helpers.DataHelper
+import h_mal.appttude.com.driver.helpers.EspressoHelper.waitForView
import org.hamcrest.CoreMatchers.allOf
import org.hamcrest.CoreMatchers.anything
+import org.hamcrest.Matcher
+import org.hamcrest.Matchers
+import java.io.File
+@SuppressWarnings("unused")
open class BaseTestRobot {
fun fillEditText(resId: Int, text: String?): ViewInteraction =
@@ -21,25 +48,133 @@ open class BaseTestRobot {
)
fun clickButton(resId: Int): ViewInteraction =
- onView((withId(resId))).perform(ViewActions.click())
+ onView((withId(resId))).perform(click())
- fun textView(resId: Int): ViewInteraction = onView(withId(resId))
+ fun matchView(resId: Int): ViewInteraction = onView(withId(resId))
+
+ fun matchViewWaitFor(resId: Int): ViewInteraction = waitForView(withId(resId))
fun matchText(viewInteraction: ViewInteraction, text: String): ViewInteraction = viewInteraction
- .check(matches(ViewMatchers.withText(text)))
+ .check(matches(withText(text)))
- fun matchText(resId: Int, text: String): ViewInteraction = matchText(textView(resId), text)
+ fun matchText(viewId: Int, textId: Int): ViewInteraction = onView(withId(viewId))
+ .check(matches(withText(textId)))
+
+ fun matchText(resId: Int, text: String): ViewInteraction = matchText(matchView(resId), text)
fun clickListItem(listRes: Int, position: Int) {
onData(anything())
.inAdapterView(allOf(withId(listRes)))
- .atPosition(position).perform(ViewActions.click())
+ .atPosition(position).perform(click())
+ }
+
+ fun scrollToRecyclerItem(recyclerId: Int, text: String): ViewInteraction? {
+ return matchView(recyclerId)
+ .perform(
+ // scrollTo will fail the test if no item matches.
+ RecyclerViewActions.scrollTo(
+ hasDescendant(withText(text))
+ )
+ )
+ }
+
+ fun scrollToRecyclerItem(recyclerId: Int, resIdForString: Int): ViewInteraction? {
+ return matchView(recyclerId)
+ .perform(
+ // scrollTo will fail the test if no item matches.
+ RecyclerViewActions.scrollTo(
+ hasDescendant(withText(resIdForString))
+ )
+ )
+ }
+
+ fun scrollToRecyclerItemByPosition(recyclerId: Int, position: Int): ViewInteraction? {
+ return matchView(recyclerId)
+ .perform(
+ // scrollTo will fail the test if no item matches.
+ RecyclerViewActions.scrollToPosition(position)
+ )
+ }
+
+ fun clickViewInRecycler(recyclerId: Int, text: String) {
+ matchView(recyclerId)
+ .perform(
+ // scrollTo will fail the test if no item matches.
+ RecyclerViewActions.actionOnItem(hasDescendant(withText(text)), click())
+ )
+ }
+
+ fun clickViewInRecycler(recyclerId: Int, resIdForString: Int) {
+ matchView(recyclerId)
+ .perform(
+ // scrollTo will fail the test if no item matches.
+ RecyclerViewActions.actionOnItem(hasDescendant(withText(resIdForString)), click())
+ )
+ }
+
+ fun clickSubViewInRecycler(recyclerId: Int, text: String, subView: Int) {
+ scrollToRecyclerItem(recyclerId, text)
+ ?.perform(
+ // scrollTo will fail the test if no item matches.
+ RecyclerViewActions.actionOnItem(
+ hasDescendant(withText(text)), object : ViewAction {
+ override fun getDescription(): String = "Matching recycler descendant"
+ override fun getConstraints(): Matcher? = isRoot()
+ override fun perform(uiController: UiController?, view: View?) {
+ view?.findViewById(subView)?.performClick()
+ }
+ }
+ )
+ )
}
fun checkErrorOnTextEntry(resId: Int, errorMessage: String): ViewInteraction =
onView(withId(resId)).check(matches(checkErrorMessage(errorMessage)))
+ fun checkImageViewHasImage(resId: Int): ViewInteraction =
+ onView(withId(resId)).check(matches(checkImage()))
+
+ fun swipeDown(resId: Int): ViewInteraction =
+ onView(withId(resId)).perform(swipeDown())
+
fun getStringFromResource(@StringRes resId: Int): String =
Resources.getSystem().getString(resId)
+ fun selectDateInPicker(year: Int, month: Int, day: Int) {
+ onView(withClassName(Matchers.equalTo(DatePicker::class.java.name))).perform(
+ PickerActions.setDate(
+ year,
+ month,
+ day
+ )
+ )
+ }
+
+ fun selectSingleImageFromGallery(filePath: FormRobot.FilePath, openSelector: () -> Unit) {
+ Intents.init()
+ // Build the result to return when the activity is launched.
+ val resultData = Intent()
+ resultData.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
+ resultData.data = Uri.fromFile(File(FormRobot.FilePath.getFilePath(filePath)))
+ val result = Instrumentation.ActivityResult(Activity.RESULT_OK, resultData)
+ // Set up result stubbing when an intent sent to image picker is seen.
+ intending(hasAction(Intent.ACTION_GET_CONTENT)).respondWith(result)
+
+ openSelector()
+ Intents.release()
+ }
+
+ fun selectMultipleImageFromGallery(filePaths: Array, openSelector: () -> Unit) {
+ Intents.init()
+ // Build the result to return when the activity is launched.
+ val resultData = Intent()
+ val clipData = DataHelper.createClipData(filePaths)
+ resultData.clipData = clipData
+ val result = Instrumentation.ActivityResult(Activity.RESULT_OK, resultData)
+ // Set up result stubbing when an intent sent to "contacts" is seen.
+ intending(IntentMatchers.toPackage("android.intent.action.PICK")).respondWith(result)
+
+ openSelector()
+ Intents.release()
+ }
}
\ No newline at end of file
diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/BaseUiTest.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/BaseUiTest.kt
index cc9e4fb..376fdf3 100644
--- a/app/src/androidTest/java/h_mal/appttude/com/driver/BaseUiTest.kt
+++ b/app/src/androidTest/java/h_mal/appttude/com/driver/BaseUiTest.kt
@@ -1,35 +1,65 @@
package h_mal.appttude.com.driver
+import android.Manifest
+import android.R
+import android.app.Activity
+import android.content.Context
+import android.os.Build
import android.view.View
+import android.view.WindowManager
import androidx.annotation.StringRes
import androidx.test.core.app.ActivityScenario
+import androidx.test.espresso.*
import androidx.test.espresso.Espresso.onView
-import androidx.test.espresso.IdlingRegistry
-import androidx.test.espresso.IdlingResource
-import androidx.test.espresso.UiController
-import androidx.test.espresso.ViewAction
-import androidx.test.espresso.matcher.ViewMatchers.isRoot
-import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.espresso.assertion.ViewAssertions.matches
+import androidx.test.espresso.matcher.ViewMatchers.*
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import androidx.test.rule.GrantPermissionRule
import h_mal.appttude.com.driver.base.BaseActivity
+import h_mal.appttude.com.driver.helpers.BaseViewAction
+import h_mal.appttude.com.driver.helpers.SnapshotRule
+import org.hamcrest.CoreMatchers
+import org.hamcrest.Description
import org.hamcrest.Matcher
+import org.hamcrest.TypeSafeMatcher
+import org.hamcrest.core.AllOf
import org.junit.After
import org.junit.Before
+import org.junit.ClassRule
+import org.junit.Rule
+import tools.fastlane.screengrab.Screengrab
+import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy
+import tools.fastlane.screengrab.locale.LocaleTestRule
-open class BaseUiTest>(
+open class BaseUiTest>(
private val activity: Class
) {
private lateinit var mActivityScenarioRule: ActivityScenario
private var mIdlingResource: IdlingResource? = null
+ private lateinit var currentActivity: Activity
+
+ @get:Rule
+ var permissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+
+ @get:Rule
+ var snapshotRule: SnapshotRule = SnapshotRule()
+
+ @Rule
+ @JvmField
+ var localeTestRule = LocaleTestRule()
+
@Before
fun setup() {
+ Screengrab.setDefaultScreenshotStrategy(UiAutomatorScreenshotStrategy())
beforeLaunch()
mActivityScenarioRule = ActivityScenario.launch(activity)
mActivityScenarioRule.onActivity {
mIdlingResource = it.getIdlingResource()!!
IdlingRegistry.getInstance().register(mIdlingResource)
+ afterLaunch(it)
}
}
@@ -41,7 +71,7 @@ open class BaseUiTest>(
}
fun getResourceString(@StringRes stringRes: Int): String {
- return InstrumentationRegistry.getInstrumentation().targetContext.resources.getString(
+ return getInstrumentation().targetContext.resources.getString(
stringRes
)
}
@@ -49,7 +79,7 @@ open class BaseUiTest>(
fun waitFor(delay: Long) {
onView(isRoot()).perform(object : ViewAction {
override fun getConstraints(): Matcher = isRoot()
- override fun getDescription(): String? = "wait for $delay milliseconds"
+ override fun getDescription(): String = "wait for $delay milliseconds"
override fun perform(uiController: UiController, v: View?) {
uiController.loopMainThreadForAtLeast(delay)
}
@@ -57,4 +87,55 @@ open class BaseUiTest>(
}
open fun beforeLaunch() {}
+ open fun afterLaunch(context: Context) {}
+
+
+ @Suppress("DEPRECATION")
+ fun checkToastMessage(message: String) {
+ onView(withText(message)).inRoot(object : TypeSafeMatcher() {
+ override fun describeTo(description: Description?) {
+ description?.appendText("is toast")
+ }
+
+ override fun matchesSafely(root: Root): Boolean {
+ root.run {
+ if (windowLayoutParams.get().type == WindowManager.LayoutParams.TYPE_TOAST) {
+ decorView.run {
+ if (windowToken === applicationWindowToken) {
+ // windowToken == appToken means this window isn't contained by any other windows.
+ // if it was a window for an activity, it would have TYPE_BASE_APPLICATION.
+ return true
+ }
+ }
+ }
+ }
+ return false
+ }
+ }
+ ).check(matches(isDisplayed()))
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
+ waitFor(3500)
+ }
+ }
+
+ fun checkSnackBarDisplayedByMessage(message: String) {
+ onView(
+ CoreMatchers.allOf(
+ withId(com.google.android.material.R.id.snackbar_text),
+ withText(message)
+ )
+ ).check(matches(isDisplayed()))
+ }
+
+ private fun getCurrentActivity(): Activity {
+ onView(AllOf.allOf(withId(R.id.content), isDisplayed()))
+ .perform(object : BaseViewAction() {
+ override fun setPerform(uiController: UiController?, view: View?) {
+ if (view?.context is Activity) {
+ currentActivity = view.context as Activity
+ }
+ }
+ })
+ return currentActivity
+ }
}
\ No newline at end of file
diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/Constants.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/Constants.kt
index 5336d08..211d073 100644
--- a/app/src/androidTest/java/h_mal/appttude/com/driver/Constants.kt
+++ b/app/src/androidTest/java/h_mal/appttude/com/driver/Constants.kt
@@ -7,4 +7,8 @@ const val deleteAccountFirebase =
"http://10.0.2.2:9099/identitytoolkit.googleapis.com/v1/accounts:delete?key=$apiKey"
-const val USER_PASSWORD = "LetMeIn123!"
\ No newline at end of file
+const val USER_PASSWORD = "LetMeIn123!"
+
+const val DRIVER_EMAIL = "existing-driver@driver.com"
+const val ADMIN_EMAIL = "admin@driver.com"
+const val PASSWORD = "test123456"
\ No newline at end of file
diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/CustomViewMatchers.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/CustomViewMatchers.kt
index 148b37a..09472ef 100644
--- a/app/src/androidTest/java/h_mal/appttude/com/driver/CustomViewMatchers.kt
+++ b/app/src/androidTest/java/h_mal/appttude/com/driver/CustomViewMatchers.kt
@@ -1,7 +1,9 @@
package h_mal.appttude.com.driver
+import android.graphics.drawable.BitmapDrawable
import android.view.View
import android.widget.EditText
+import android.widget.ImageView
import com.google.android.material.textfield.TextInputLayout
import org.hamcrest.Description
import org.hamcrest.Matcher
@@ -11,7 +13,7 @@ import org.hamcrest.TypeSafeMatcher
/**
* Matcher for testing error of TextInputLayout
*/
-fun checkErrorMessage(expectedErrorText: String): Matcher? {
+fun checkErrorMessage(expectedErrorText: String): Matcher {
return object : TypeSafeMatcher() {
override fun matchesSafely(view: View?): Boolean {
if (view is EditText) {
@@ -28,3 +30,25 @@ fun checkErrorMessage(expectedErrorText: String): Matcher? {
}
}
+fun checkImage(): Matcher {
+ return object : TypeSafeMatcher() {
+ override fun matchesSafely(view: View?): Boolean {
+ if (view is ImageView) {
+ return hasImage(view)
+ }
+ return false
+ }
+
+ override fun describeTo(d: Description?) {}
+
+ private fun hasImage(view: ImageView): Boolean {
+ val drawable = view.drawable
+ var hasImage = drawable != null
+ if (hasImage && drawable is BitmapDrawable) {
+ hasImage = drawable.bitmap != null
+ }
+ return hasImage
+ }
+ }
+}
+
diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/FirebaseTest.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/FirebaseTest.kt
index 00302cc..6c93287 100644
--- a/app/src/androidTest/java/h_mal/appttude/com/driver/FirebaseTest.kt
+++ b/app/src/androidTest/java/h_mal/appttude/com/driver/FirebaseTest.kt
@@ -5,18 +5,23 @@ import com.google.firebase.database.FirebaseDatabase
import com.google.firebase.storage.FirebaseStorage
import h_mal.appttude.com.driver.base.BaseActivity
import h_mal.appttude.com.driver.data.FirebaseAuthSource
+import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
+import h_mal.appttude.com.driver.data.FirebaseStorageSource
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.tasks.await
import org.junit.After
import org.junit.BeforeClass
-open class FirebaseTest>(
+open class FirebaseTest>(
activity: Class,
private val registered: Boolean = false,
- private val signedIn: Boolean = false
+ private val signedIn: Boolean = false,
+ private val signOutAfterTest: Boolean = true
) : BaseUiTest(activity) {
private val firebaseAuthSource by lazy { FirebaseAuthSource() }
+ private val firebaseDatabaseSource by lazy { FirebaseDatabaseSource() }
+ private val firebaseStorageSource by lazy { FirebaseStorageSource() }
private var email: String? = null
@@ -45,9 +50,10 @@ open class FirebaseTest>(
}
@After
- fun tearDownFirebase() = runBlocking {
- removeUser()
- firebaseAuthSource.logOut()
+ fun tearDownFirebase() {
+ if (signOutAfterTest) {
+ firebaseAuthSource.logOut()
+ }
}
suspend fun setupUser(
@@ -58,6 +64,14 @@ open class FirebaseTest>(
firebaseAuthSource.registerUser(signInEmail, password).await().user
}
+ suspend fun login(
+ signInEmail: String,
+ password: String
+ ) {
+ email = signInEmail
+ firebaseAuthSource.signIn(signInEmail, password).await()
+ }
+
// remove the user we created for testing
suspend fun removeUser() {
try {
@@ -82,9 +96,6 @@ open class FirebaseTest>(
}
fun getEmail(): String? {
- firebaseAuthSource.getUser()?.email?.let {
- return it
- }
- return email
+ return firebaseAuthSource.getUser()?.email ?: email
}
}
\ No newline at end of file
diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/FormRobot.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/FormRobot.kt
new file mode 100644
index 0000000..24f2967
--- /dev/null
+++ b/app/src/androidTest/java/h_mal/appttude/com/driver/FormRobot.kt
@@ -0,0 +1,46 @@
+package h_mal.appttude.com.driver
+
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.action.ViewActions.click
+import androidx.test.espresso.matcher.ViewMatchers.withId
+import h_mal.appttude.com.driver.helpers.getImagePath
+
+
+open class FormRobot : BaseTestRobot() {
+ fun submit() = clickButton(R.id.submit)
+ fun setDate(datePickerLaunchViewId: Int, year: Int, monthOfYear: Int, dayOfMonth: Int) {
+ onView(withId(datePickerLaunchViewId)).perform(click())
+ selectDateInPicker(year, monthOfYear, dayOfMonth)
+ // click ok in date picker
+ onView(withId(android.R.id.button1)).perform(click())
+ }
+
+ fun selectSingleImage(imagePickerLauncherViewId: Int, filePath: FilePath) {
+ selectSingleImageFromGallery(filePath) {
+ onView(withId(imagePickerLauncherViewId)).perform(click())
+ }
+ // click ok in date picker
+ }
+
+ fun selectMultipleImage(imagePickerLauncherViewId: Int, filePaths: Array) {
+ selectMultipleImageFromGallery(filePaths) {
+ onView(withId(imagePickerLauncherViewId)).perform(click())
+ }
+ }
+
+ enum class FilePath(val path: String) {
+ PROFILE_PIC("driver_profile_pic.jpg"),
+ INSURANCE("driver_insurance.jpg"),
+ PRIVATE_HIRE("driver_license_private_hire.jpg"),
+ PRIVATE_HIRE_CAR("driver_license_private_hire_car.jpg"),
+ LOGBOOK("driver_logbook.jpg"),
+ MOT("driver_mot.jpg"),
+ LICENSE("driver_license_driver.jpg");
+
+ companion object {
+ fun getFilePath(filePath: FilePath): String {
+ return getImagePath(filePath.path)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/WebUtils.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/WebUtils.kt
index 1d82427..4b6b6c8 100644
--- a/app/src/androidTest/java/h_mal/appttude/com/driver/WebUtils.kt
+++ b/app/src/androidTest/java/h_mal/appttude/com/driver/WebUtils.kt
@@ -3,8 +3,12 @@ package h_mal.appttude.com.driver
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import kotlinx.coroutines.suspendCancellableCoroutine
-import okhttp3.*
+import okhttp3.Call
+import okhttp3.Callback
+import okhttp3.OkHttpClient
+import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
+import okhttp3.Response
import java.io.IOException
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/firebase/api/FirebaseApi.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/firebase/api/FirebaseApi.kt
new file mode 100644
index 0000000..7c9a9f0
--- /dev/null
+++ b/app/src/androidTest/java/h_mal/appttude/com/driver/firebase/api/FirebaseApi.kt
@@ -0,0 +1,54 @@
+package h_mal.appttude.com.driver.firebase.api
+
+import h_mal.appttude.com.driver.firebase.model.*
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import retrofit2.Response
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+import retrofit2.http.Body
+import retrofit2.http.PUT
+
+interface FirebaseApi {
+
+ @PUT("v1/accounts:signUp")
+ suspend fun signUp(@Body request: SignUpRequest): Response
+
+ @PUT("v1/accounts:signInWithPassword")
+ suspend fun signInWithPassword(@Body request: SignUpRequest): Response
+
+ @PUT("v1/accounts:sendOobCode")
+ suspend fun sendOobCode(@Body request: Map): Response
+
+ @PUT("v1/accounts:resetPassword")
+ suspend fun resetPassword(@Body request: ResetPasswordRequest): Response
+
+ // invoke method creating an invocation of the api call
+ companion object {
+ operator fun invoke(): FirebaseApi {
+ val host = "10.0.2.2"
+ val baseUrl = "http://$host:9099/identitytoolkit.googleapis.com/"
+
+ val okkHttpclient = OkHttpClient.Builder()
+ .addInterceptor {
+ val original = it.request()
+ val url = original.url.newBuilder()
+ .addQueryParameter("key", "apikeydfasdfasdfasdf")
+ .build()
+
+ val requestBuilder = original.newBuilder().url(url)
+ val request: Request = requestBuilder.build()
+ it.proceed(request)
+ }
+ .build()
+
+ // creation of retrofit class
+ return Retrofit.Builder()
+ .client(okkHttpclient)
+ .baseUrl(baseUrl)
+ .addConverterFactory(GsonConverterFactory.create())
+ .build()
+ .create(FirebaseApi::class.java)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/firebase/api/FirebaseApiModule.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/firebase/api/FirebaseApiModule.kt
new file mode 100644
index 0000000..6eeb6d7
--- /dev/null
+++ b/app/src/androidTest/java/h_mal/appttude/com/driver/firebase/api/FirebaseApiModule.kt
@@ -0,0 +1,26 @@
+package h_mal.appttude.com.driver.firebase.api
+
+import h_mal.appttude.com.driver.firebase.model.SignUpRequest
+import h_mal.appttude.com.driver.firebase.model.SignUpResponse
+import kotlinx.coroutines.runBlocking
+
+class FirebaseApiModule {
+
+ private val firebaseApi = FirebaseApi()
+
+ fun signUp(email: String, password: String): SignUpResponse? {
+ return runBlocking {
+ val req = SignUpRequest(email = email, password = password)
+ val response = firebaseApi.signUp(req)
+ response.body()
+ }
+ }
+
+ fun signIn(email: String, password: String): SignUpResponse? {
+ return runBlocking {
+ val req = SignUpRequest(email = email, password = password)
+ val response = firebaseApi.signInWithPassword(req)
+ response.body()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/firebase/api/NetworkConnectionInterceptor.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/firebase/api/NetworkConnectionInterceptor.kt
new file mode 100644
index 0000000..c7084b4
--- /dev/null
+++ b/app/src/androidTest/java/h_mal/appttude/com/driver/firebase/api/NetworkConnectionInterceptor.kt
@@ -0,0 +1,38 @@
+package h_mal.appttude.com.driver.firebase.api
+
+import android.content.Context
+import android.net.ConnectivityManager
+import android.net.NetworkCapabilities
+import okhttp3.Interceptor
+import java.io.IOException
+
+class NetworkConnectionInterceptor(
+ context: Context
+) : Interceptor {
+
+ private val applicationContext = context.applicationContext
+
+ override fun intercept(chain: Interceptor.Chain): okhttp3.Response {
+ if (!isInternetAvailable()) {
+ throw IOException("Make sure you have an active data connection")
+ }
+ return chain.proceed(chain.request())
+ }
+
+ private fun isInternetAvailable(): Boolean {
+ var result = false
+ val connectivityManager =
+ applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
+ connectivityManager?.let {
+ it.getNetworkCapabilities(connectivityManager.activeNetwork)?.apply {
+ result = when {
+ hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
+ hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
+ else -> false
+ }
+ }
+ }
+ return result
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/firebase/model/OobCodeResponse.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/firebase/model/OobCodeResponse.kt
new file mode 100644
index 0000000..a5e83c7
--- /dev/null
+++ b/app/src/androidTest/java/h_mal/appttude/com/driver/firebase/model/OobCodeResponse.kt
@@ -0,0 +1,9 @@
+package h_mal.appttude.com.driver.firebase.model
+
+data class OobCodeResponse(
+ val kind: String? = null,
+ val oobLink: String? = null,
+ val oobCode: String? = null,
+ val email: String? = null
+)
+
diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/firebase/model/ResetPasswordRequest.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/firebase/model/ResetPasswordRequest.kt
new file mode 100644
index 0000000..02d2893
--- /dev/null
+++ b/app/src/androidTest/java/h_mal/appttude/com/driver/firebase/model/ResetPasswordRequest.kt
@@ -0,0 +1,10 @@
+package h_mal.appttude.com.driver.firebase.model
+
+data class ResetPasswordRequest(
+ val oldPassword: String? = null,
+ val tenantId: String? = null,
+ val newPassword: String? = null,
+ val oobCode: String? = null,
+ val email: String? = null
+)
+
diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/firebase/model/ResetPasswordResponse.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/firebase/model/ResetPasswordResponse.kt
new file mode 100644
index 0000000..9a012f2
--- /dev/null
+++ b/app/src/androidTest/java/h_mal/appttude/com/driver/firebase/model/ResetPasswordResponse.kt
@@ -0,0 +1,9 @@
+package h_mal.appttude.com.driver.firebase.model
+
+data class ResetPasswordResponse(
+ val requestType: String? = null,
+ val kind: String? = null,
+ val newEmail: String? = null,
+ val email: String? = null
+)
+
diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/firebase/model/SignUpRequest.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/firebase/model/SignUpRequest.kt
new file mode 100644
index 0000000..35f3abc
--- /dev/null
+++ b/app/src/androidTest/java/h_mal/appttude/com/driver/firebase/model/SignUpRequest.kt
@@ -0,0 +1,7 @@
+package h_mal.appttude.com.driver.firebase.model
+
+data class SignUpRequest(
+ val password: String? = null,
+ val email: String? = null
+)
+
diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/firebase/SignUpResponse.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/firebase/model/SignUpResponse.kt
similarity index 81%
rename from app/src/androidTest/java/h_mal/appttude/com/driver/firebase/SignUpResponse.kt
rename to app/src/androidTest/java/h_mal/appttude/com/driver/firebase/model/SignUpResponse.kt
index 4ae760e..8ca9e4b 100644
--- a/app/src/androidTest/java/h_mal/appttude/com/driver/firebase/SignUpResponse.kt
+++ b/app/src/androidTest/java/h_mal/appttude/com/driver/firebase/model/SignUpResponse.kt
@@ -1,4 +1,4 @@
-package h_mal.appttude.com.driver.firebase
+package h_mal.appttude.com.driver.firebase.model
data class SignUpResponse(
val expiresIn: String? = null,
diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/BaseMatcher.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/BaseMatcher.kt
new file mode 100644
index 0000000..b13e895
--- /dev/null
+++ b/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/BaseMatcher.kt
@@ -0,0 +1,17 @@
+package h_mal.appttude.com.driver.helpers
+
+import android.view.View
+import org.hamcrest.BaseMatcher
+import org.hamcrest.Description
+
+class BaseMatcher: BaseMatcher() {
+ override fun describeTo(description: Description?) {
+ TODO("Not yet implemented")
+ }
+
+ override fun matches(actual: Any?): Boolean {
+ TODO("Not yet implemented")
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/BaseViewAction.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/BaseViewAction.kt
new file mode 100644
index 0000000..28be005
--- /dev/null
+++ b/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/BaseViewAction.kt
@@ -0,0 +1,27 @@
+package h_mal.appttude.com.driver.helpers
+
+import android.view.View
+import androidx.test.espresso.UiController
+import androidx.test.espresso.ViewAction
+import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom
+import org.hamcrest.Matcher
+
+open class BaseViewAction: ViewAction {
+ override fun getDescription(): String? = setDescription()
+
+ override fun getConstraints(): Matcher = setConstraints()
+
+ override fun perform(uiController: UiController?, view: View?) {
+ setPerform(uiController, view)
+ }
+
+ open fun setDescription(): String? {
+ return null
+ }
+
+ open fun setConstraints(): Matcher {
+ return isAssignableFrom(View::class.java)
+ }
+
+ open fun setPerform(uiController: UiController?, view: View?) { }
+}
\ No newline at end of file
diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/Constants.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/Constants.kt
new file mode 100644
index 0000000..31ba4f7
--- /dev/null
+++ b/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/Constants.kt
@@ -0,0 +1,14 @@
+package h_mal.appttude.com.driver.helpers
+
+import android.os.Environment
+import java.io.File
+
+/**
+ * File paths for images on device
+ */
+fun getImagePath(imageConst: String): String {
+ return File(
+ Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),
+ "/Camera/images/$imageConst"
+ ).absolutePath
+}
\ No newline at end of file
diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/DataHelper.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/DataHelper.kt
new file mode 100644
index 0000000..bc2e262
--- /dev/null
+++ b/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/DataHelper.kt
@@ -0,0 +1,33 @@
+package h_mal.appttude.com.driver.helpers
+
+import android.content.ClipData
+import android.content.ClipData.Item
+import android.net.Uri
+import java.io.File
+
+object DataHelper {
+
+ fun createClipItem(filePath: String) = Item(
+ Uri.fromFile(
+ File(filePath)
+ )
+ )
+
+ fun createClipData(item: Item, mimeType: String = "text/uri-list") =
+ ClipData(null, arrayOf(mimeType), item)
+
+ fun createClipData(filePath: String) = createClipData(createClipItem(filePath))
+
+ fun createClipData(filePaths: Array): ClipData {
+ val clipData = createClipData(filePaths[0])
+ val remainingFiles = filePaths.copyOfRange(1, filePaths.size - 1)
+ clipData.addFilePaths(remainingFiles)
+ return clipData
+ }
+
+ fun createClipData(uri: Uri) = createClipData(Item(uri))
+
+ fun ClipData.addFilePaths(filePaths: Array) {
+ filePaths.forEach { addItem(createClipItem(it)) }
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/EspressoHelper.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/EspressoHelper.kt
new file mode 100644
index 0000000..08ade1e
--- /dev/null
+++ b/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/EspressoHelper.kt
@@ -0,0 +1,123 @@
+package h_mal.appttude.com.driver.helpers
+
+import android.os.SystemClock.sleep
+import android.view.View
+import android.widget.CheckBox
+import android.widget.Checkable
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.NoMatchingViewException
+import androidx.test.espresso.UiController
+import androidx.test.espresso.ViewAction
+import androidx.test.espresso.ViewInteraction
+import androidx.test.espresso.matcher.ViewMatchers.isRoot
+import androidx.test.espresso.util.TreeIterables
+import org.hamcrest.BaseMatcher
+import org.hamcrest.CoreMatchers.isA
+import org.hamcrest.Description
+import org.hamcrest.Matcher
+
+
+object EspressoHelper {
+
+ /**
+ * Perform action of waiting for a certain view within a single root view
+ * @param viewMatcher Generic Matcher used to find our view
+ */
+ fun searchFor(viewMatcher: Matcher): ViewAction {
+
+ return object : ViewAction {
+
+ override fun getConstraints(): Matcher = isRoot()
+ override fun getDescription(): String {
+ return "searching for view $this in the root view"
+ }
+
+ override fun perform(uiController: UiController, view: View) {
+ var tries = 0
+ val childViews: Iterable = TreeIterables.breadthFirstViewTraversal(view)
+
+ // Look for the match in the tree of childviews
+ childViews.forEach {
+ tries++
+ if (viewMatcher.matches(it)) {
+ // found the view
+ return
+ }
+ }
+
+ throw NoMatchingViewException.Builder()
+ .withRootView(view)
+ .withViewMatcher(viewMatcher)
+ .build()
+ }
+ }
+ }
+
+ /**
+ * Performs an action to check/uncheck a checkbox
+ *
+ */
+ fun setChecked(checked: Boolean): ViewAction {
+ return object : ViewAction {
+ override fun getConstraints(): BaseMatcher {
+ return object : BaseMatcher() {
+ override fun describeTo(description: Description?) {}
+
+ override fun matches(actual: Any?): Boolean {
+ return isA(CheckBox::class.java).matches(actual)
+ }
+ }
+ }
+
+ override fun getDescription(): String {
+ return ""
+ }
+
+ override fun perform(uiController: UiController, view: View) {
+ val checkableView = view as Checkable
+ checkableView.isChecked = checked
+ }
+ }
+ }
+
+ /**
+ * Perform action of implicitly waiting for a certain view.
+ * This differs from EspressoExtensions.searchFor in that,
+ * upon failure to locate an element, it will fetch a new root view
+ * in which to traverse searching for our @param match
+ *
+ * @param viewMatcher ViewMatcher used to find our view
+ */
+ fun waitForView(
+ viewMatcher: Matcher,
+ waitMillis: Int = 5000,
+ waitMillisPerTry: Long = 100
+ ): ViewInteraction {
+
+ // Derive the max tries
+ val maxTries = waitMillis / waitMillisPerTry.toInt()
+
+ var tries = 0
+
+ for (i in 0..maxTries)
+ try {
+ // Track the amount of times we've tried
+ tries++
+
+ // Search the root for the view
+ onView(isRoot()).perform(searchFor(viewMatcher))
+
+ // If we're here, we found our view. Now return it
+ return onView(viewMatcher)
+
+ } catch (e: Exception) {
+
+ if (tries == maxTries) {
+ throw e
+ }
+ sleep(waitMillisPerTry)
+ }
+
+ throw Exception("Error finding a view matching $viewMatcher")
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/SnapshotRule.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/SnapshotRule.kt
new file mode 100644
index 0000000..90a9911
--- /dev/null
+++ b/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/SnapshotRule.kt
@@ -0,0 +1,20 @@
+package h_mal.appttude.com.driver.helpers
+
+import org.junit.rules.TestWatcher
+import org.junit.runner.Description
+import tools.fastlane.screengrab.Screengrab
+import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy
+
+/**
+ * Junit rule that takes a screenshot when a test fails.
+ */
+class SnapshotRule : TestWatcher() {
+ override fun failed(e: Throwable, description: Description) {
+ // Catch a screenshot on failure
+ Screengrab.screenshot("FAILURE-" + getScreenshotName(description))
+ }
+
+ fun getScreenshotName(description: Description): String {
+ return description.className.replace(".", "-") + "_" + description.methodName.replace(".", "-")
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/LoginRobot.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/robots/LoginRobot.kt
similarity index 74%
rename from app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/LoginRobot.kt
rename to app/src/androidTest/java/h_mal/appttude/com/driver/robots/LoginRobot.kt
index c7a76f9..39d005e 100644
--- a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/LoginRobot.kt
+++ b/app/src/androidTest/java/h_mal/appttude/com/driver/robots/LoginRobot.kt
@@ -1,6 +1,7 @@
package h_mal.appttude.com.driver.robots
import h_mal.appttude.com.driver.BaseTestRobot
+import h_mal.appttude.com.driver.PASSWORD
import h_mal.appttude.com.driver.R
@@ -21,4 +22,11 @@ class LoginRobot : BaseTestRobot() {
fun checkPasswordError(err: String) = checkErrorOnTextEntry(R.id.password, err)
+ fun attemptLogin(emailAddress: String, password: String = PASSWORD) {
+ matchViewWaitFor(R.id.email)
+ setEmail(emailAddress)
+ setPassword(password)
+ clickLogin()
+ }
+
}
\ No newline at end of file
diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/RegisterRobot.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/robots/RegisterRobot.kt
similarity index 84%
rename from app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/RegisterRobot.kt
rename to app/src/androidTest/java/h_mal/appttude/com/driver/robots/RegisterRobot.kt
index d0bced1..b334357 100644
--- a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/RegisterRobot.kt
+++ b/app/src/androidTest/java/h_mal/appttude/com/driver/robots/RegisterRobot.kt
@@ -8,17 +8,17 @@ class RegisterRobot : BaseTestRobot() {
fun setName(name: String) = fillEditText(R.id.name_register, name)
- fun setEmail(email: String) = fillEditText(R.id.email_register, email)
+ fun setEmail(email: String) = fillEditText(R.id.email, email)
fun setPassword(pass: String) = fillEditText(R.id.password_top, pass)
fun setPasswordConfirm(pass: String) = fillEditText(R.id.password_bottom, pass)
- fun clickLogin() = clickButton(R.id.email_sign_up)
+ fun clickLogin() = clickButton(R.id.submit)
fun checkNameError(err: String) = checkErrorOnTextEntry(R.id.name_register, err)
- fun checkEmailError(err: String) = checkErrorOnTextEntry(R.id.email_register, err)
+ fun checkEmailError(err: String) = checkErrorOnTextEntry(R.id.email, err)
fun checkPasswordError(err: String) = checkErrorOnTextEntry(R.id.password_top, err)
diff --git a/app/src/androidTestAdmin/java/h_mal/appttude/com/driver/robots/ApproverRobot.kt b/app/src/androidTestAdmin/java/h_mal/appttude/com/driver/robots/ApproverRobot.kt
new file mode 100644
index 0000000..22a74a0
--- /dev/null
+++ b/app/src/androidTestAdmin/java/h_mal/appttude/com/driver/robots/ApproverRobot.kt
@@ -0,0 +1,13 @@
+package h_mal.appttude.com.driver.robots
+
+import h_mal.appttude.com.driver.BaseTestRobot
+import h_mal.appttude.com.driver.R
+
+
+fun approver(func: ApproverRobot.() -> Unit) = ApproverRobot().apply { func() }
+class ApproverRobot : BaseTestRobot() {
+
+ fun clickApprove() = clickButton(R.id.approve)
+ fun clickDecline() = clickButton(R.id.decline)
+
+}
\ No newline at end of file
diff --git a/app/src/androidTestAdmin/java/h_mal/appttude/com/driver/robots/DriverOverviewRobot.kt b/app/src/androidTestAdmin/java/h_mal/appttude/com/driver/robots/DriverOverviewRobot.kt
new file mode 100644
index 0000000..b0b2470
--- /dev/null
+++ b/app/src/androidTestAdmin/java/h_mal/appttude/com/driver/robots/DriverOverviewRobot.kt
@@ -0,0 +1,36 @@
+package h_mal.appttude.com.driver.robots
+
+import android.view.View
+import androidx.test.espresso.Espresso.onData
+import androidx.test.espresso.action.ViewActions.click
+import androidx.test.espresso.assertion.ViewAssertions.matches
+import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
+import androidx.test.espresso.matcher.ViewMatchers.withId
+import androidx.test.espresso.matcher.ViewMatchers.withText
+import h_mal.appttude.com.driver.BaseTestRobot
+import h_mal.appttude.com.driver.R
+import h_mal.appttude.com.driver.helpers.EspressoHelper.waitForView
+import org.hamcrest.BaseMatcher
+import org.hamcrest.CoreMatchers.anything
+
+
+fun driverOverview(func: DriverOverviewRobot.() -> Unit) = DriverOverviewRobot().apply { func() }
+class DriverOverviewRobot : BaseTestRobot() {
+
+ fun clickOnItemAtPosition(index: Int) =
+ onData(anything())
+ .inAdapterView(withId(R.id.approvals_list))
+ .atPosition(index)
+ .perform(click())
+
+ fun matchView(position: Int, status: String) =
+ onData(anything())
+ .inAdapterView(withId(R.id.approvals_list))
+ .atPosition(position)
+ .onChildView(withText(status))
+ .check(matches(isDisplayed()))
+
+ fun waitForListViewToDisplay() {
+ waitForView(withId(R.id.approval_status))
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTestAdmin/java/h_mal/appttude/com/driver/robots/HomeAdminRobot.kt b/app/src/androidTestAdmin/java/h_mal/appttude/com/driver/robots/HomeAdminRobot.kt
new file mode 100644
index 0000000..2cd8bfb
--- /dev/null
+++ b/app/src/androidTestAdmin/java/h_mal/appttude/com/driver/robots/HomeAdminRobot.kt
@@ -0,0 +1,53 @@
+package h_mal.appttude.com.driver.robots
+
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.action.ViewActions
+import androidx.test.espresso.contrib.DrawerActions
+import androidx.test.espresso.matcher.ViewMatchers.withId
+import androidx.test.espresso.matcher.ViewMatchers.withTagKey
+import h_mal.appttude.com.driver.BaseTestRobot
+import h_mal.appttude.com.driver.R
+import h_mal.appttude.com.driver.base.CustomViewHolder
+import h_mal.appttude.com.driver.model.DatabaseStatus
+
+fun homeAdmin(func: HomeAdminRobot.() -> Unit) = HomeAdminRobot().apply { func() }
+class HomeAdminRobot : BaseTestRobot() {
+
+ fun waitUntilDisplayed() {
+ matchViewWaitFor(R.id.recycler_view)
+ }
+
+ fun openDrawer() {
+ onView(withId(R.id.drawer_layout)).perform(DrawerActions.open())
+ }
+
+ fun closeDrawer() {
+ onView(withId(R.id.drawer_layout)).perform(DrawerActions.close())
+ }
+
+ fun updateProfile() {
+ openDrawer()
+ clickButton(R.id.nav_user_settings)
+ }
+
+ fun clickOnItem(anyText: String) =
+ clickViewInRecycler>(R.id.recycler_view, anyText)
+
+ fun clickOnDriverIdentifier(anyText: String) =
+ clickSubViewInRecycler>(R.id.recycler_view, anyText, R.id.driver_no)
+
+ fun submitDialog(text: String) {
+ onView(withTagKey(R.string.driver_identifier)).perform(
+ ViewActions.replaceText(text),
+ ViewActions.closeSoftKeyboard()
+ )
+ // Click OK
+ onView(withId(android.R.id.button1)).perform(ViewActions.click())
+ }
+
+ fun showNoPermissionsDisplay() {
+ matchViewWaitFor(R.id.header)
+ matchText(R.id.header, DatabaseStatus.NO_PERMISSION.header)
+ matchText(R.id.subtext, DatabaseStatus.NO_PERMISSION.subtext)
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTestAdmin/java/h_mal/appttude/com/driver/tests/AdminBaseTest.kt b/app/src/androidTestAdmin/java/h_mal/appttude/com/driver/tests/AdminBaseTest.kt
new file mode 100644
index 0000000..60a6772
--- /dev/null
+++ b/app/src/androidTestAdmin/java/h_mal/appttude/com/driver/tests/AdminBaseTest.kt
@@ -0,0 +1,15 @@
+package h_mal.appttude.com.driver.tests
+
+import h_mal.appttude.com.driver.ADMIN_EMAIL
+import h_mal.appttude.com.driver.FirebaseTest
+import h_mal.appttude.com.driver.PASSWORD
+import h_mal.appttude.com.driver.ui.MainActivity
+import kotlinx.coroutines.runBlocking
+
+open class AdminBaseTest: FirebaseTest(MainActivity::class.java) {
+ override fun beforeLaunch() {
+ runBlocking {
+ login(ADMIN_EMAIL, PASSWORD)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTestAdmin/java/h_mal/appttude/com/driver/tests/DocumentApproverTest.kt b/app/src/androidTestAdmin/java/h_mal/appttude/com/driver/tests/DocumentApproverTest.kt
new file mode 100644
index 0000000..d538e1d
--- /dev/null
+++ b/app/src/androidTestAdmin/java/h_mal/appttude/com/driver/tests/DocumentApproverTest.kt
@@ -0,0 +1,89 @@
+package h_mal.appttude.com.driver.tests
+
+import androidx.test.espresso.Espresso
+import h_mal.appttude.com.driver.R
+import h_mal.appttude.com.driver.robots.approver
+import h_mal.appttude.com.driver.robots.driverOverview
+import h_mal.appttude.com.driver.robots.homeAdmin
+import org.junit.Test
+
+class DocumentApproverTest : AdminBaseTest() {
+
+ @Test
+ fun loginAsAdmin_approveDocumentForDriver_documentApproved() {
+ homeAdmin {
+ waitUntilDisplayed()
+ clickOnItem("kabirmhkhan@gmail.com")
+ }
+ // Approve check
+ driverOverview {
+ waitForListViewToDisplay()
+ clickOnItemAtPosition(0)
+ }
+ approver {
+ clickApprove()
+ checkToastMessage("Document already approved")
+ Espresso.pressBack()
+ }
+ driverOverview {
+ waitForListViewToDisplay()
+ clickOnItemAtPosition(2)
+ }
+ approver {
+ clickApprove()
+ Espresso.pressBack()
+ }
+ driverOverview {
+ waitForListViewToDisplay()
+ matchView(2, getResourceString(R.string.approved))
+ }
+ }
+
+ @Test
+ fun loginAsAdmin_declineDocumentForDriver_documentDeclined() {
+ homeAdmin {
+ waitUntilDisplayed()
+ // TODO: find a better way to waitw
+ waitFor(1200)
+ clickOnItem("kabirmhkhan@gmail.com")
+ }
+
+ // Decline check
+ driverOverview {
+ waitForListViewToDisplay()
+ clickOnItemAtPosition(3)
+ }
+ approver {
+ clickDecline()
+ checkToastMessage("Document already declined")
+ Espresso.pressBack()
+ }
+ driverOverview {
+ waitForListViewToDisplay()
+ clickOnItemAtPosition(1)
+ }
+ approver {
+ clickDecline()
+ Espresso.pressBack()
+ }
+ driverOverview {
+ waitForListViewToDisplay()
+ matchView(1, getResourceString(R.string.denied))
+ }
+ }
+
+ @Test
+ fun loginAsAdmin_verifyNoDocumentForNewDriver() {
+ homeAdmin {
+ waitUntilDisplayed()
+ clickOnItem("fanasid@gmail.com")
+ }
+ driverOverview {
+ waitForListViewToDisplay()
+ matchView(0, getResourceString(R.string.not_submitted))
+ clickOnItemAtPosition(0)
+ matchView(0, getResourceString(R.string.not_submitted))
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/androidTestAdmin/java/h_mal/appttude/com/driver/tests/UserListTest.kt b/app/src/androidTestAdmin/java/h_mal/appttude/com/driver/tests/UserListTest.kt
new file mode 100644
index 0000000..d932b4b
--- /dev/null
+++ b/app/src/androidTestAdmin/java/h_mal/appttude/com/driver/tests/UserListTest.kt
@@ -0,0 +1,36 @@
+package h_mal.appttude.com.driver.tests
+
+import h_mal.appttude.com.driver.ADMIN_EMAIL
+import h_mal.appttude.com.driver.DRIVER_EMAIL
+import h_mal.appttude.com.driver.FirebaseTest
+import h_mal.appttude.com.driver.robots.homeAdmin
+import h_mal.appttude.com.driver.robots.login
+import h_mal.appttude.com.driver.ui.user.LoginActivity
+import org.junit.Test
+import java.io.IOException
+
+class UserListTest : FirebaseTest(LoginActivity::class.java) {
+
+ @Test
+ fun loginAsAdmin_updateDriverIdentifier_loggedIn() {
+ login {
+ attemptLogin(ADMIN_EMAIL)
+ }
+ homeAdmin {
+ clickOnDriverIdentifier("rsaif660@gmail.com")
+ submitDialog("ID45")
+ }
+ }
+
+ @Test
+ fun loginAsUser_unableToSeeDrivers_loggedIn() {
+ // Test fails on CI
+// login {
+// attemptLogin(DRIVER_EMAIL)
+// }
+// homeAdmin {
+// showNoPermissionsDisplay()
+// }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/DeleteRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/DeleteRobot.kt
new file mode 100644
index 0000000..9df821e
--- /dev/null
+++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/DeleteRobot.kt
@@ -0,0 +1,17 @@
+package h_mal.appttude.com.driver.robots
+
+import h_mal.appttude.com.driver.FormRobot
+import h_mal.appttude.com.driver.R
+
+fun delete(func: DeleteRobot.() -> Unit) = DeleteRobot().apply { func() }
+class DeleteRobot : FormRobot() {
+
+ fun enterEmail(email: String) = fillEditText(R.id.email_update, email)
+ fun enterPassword(password: String) = fillEditText(R.id.password_top, password)
+
+ fun submitForm(email: String, password: String) {
+ enterEmail(email)
+ enterPassword(password)
+ submit()
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/DriverScreenRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/DriverScreenRobot.kt
new file mode 100644
index 0000000..554f19c
--- /dev/null
+++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/DriverScreenRobot.kt
@@ -0,0 +1,13 @@
+package h_mal.appttude.com.driver.robots
+
+import h_mal.appttude.com.driver.BaseTestRobot
+import h_mal.appttude.com.driver.R
+
+fun driverScreen(func: DriverScreenRobot.() -> Unit) = DriverScreenRobot().apply { func() }
+class DriverScreenRobot : BaseTestRobot() {
+
+ fun driverProfile() = clickButton(R.id.driver_prof)
+ fun privateHireLicense() = clickButton(R.id.private_hire)
+ fun driverLicense() = clickButton(R.id.drivers_license)
+
+}
\ No newline at end of file
diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/HomeRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/HomeRobot.kt
index 50148c3..7e4fe9f 100644
--- a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/HomeRobot.kt
+++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/HomeRobot.kt
@@ -1,11 +1,31 @@
package h_mal.appttude.com.driver.robots
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.contrib.DrawerActions
+import androidx.test.espresso.matcher.ViewMatchers.withId
import h_mal.appttude.com.driver.BaseTestRobot
import h_mal.appttude.com.driver.R
fun home(func: HomeRobot.() -> Unit) = HomeRobot().apply { func() }
class HomeRobot : BaseTestRobot() {
- fun checkTitleExists(title: String) = matchText(R.id.prova_title_tv, title)
+ fun checkTitleExists(title: String) = matchText(matchViewWaitFor(R.id.prova_title_tv), title)
+ fun openDrawer() {
+ onView(withId(R.id.drawer_layout)).perform(DrawerActions.open())
+ }
+
+ fun closeDrawer() {
+ onView(withId(R.id.drawer_layout)).perform(DrawerActions.close())
+ }
+
+ fun updateProfile() {
+ openDrawer()
+ clickButton(R.id.nav_user_settings)
+ }
+
+ fun openDriverProfile() = clickButton(R.id.driver)
+ fun openVehicleProfile() = clickButton(R.id.car)
+
+ fun requestProfile() = clickButton(R.id.request_driver_button)
}
\ No newline at end of file
diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/UpdateEmailRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/UpdateEmailRobot.kt
new file mode 100644
index 0000000..5170234
--- /dev/null
+++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/UpdateEmailRobot.kt
@@ -0,0 +1,19 @@
+package h_mal.appttude.com.driver.robots
+
+import h_mal.appttude.com.driver.FormRobot
+import h_mal.appttude.com.driver.R
+
+fun updateEmail(func: UpdateEmailRobot.() -> Unit) = UpdateEmailRobot().apply { func() }
+class UpdateEmailRobot : FormRobot() {
+
+ fun enterEmail(email: String) = fillEditText(R.id.email_update, email)
+ fun enterPassword(password: String) = fillEditText(R.id.password_top, password)
+ fun enterNewEmail(email: String) = fillEditText(R.id.new_email, email)
+
+ fun submitForm(email: String, password: String, newEmail: String) {
+ enterEmail(email)
+ enterPassword(password)
+ enterNewEmail(newEmail)
+ submit()
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/UpdatePasswordRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/UpdatePasswordRobot.kt
new file mode 100644
index 0000000..b3b44f0
--- /dev/null
+++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/UpdatePasswordRobot.kt
@@ -0,0 +1,20 @@
+package h_mal.appttude.com.driver.robots
+
+import h_mal.appttude.com.driver.FormRobot
+import h_mal.appttude.com.driver.R
+
+fun updatePassword(func: UpdatePasswordRobot.() -> Unit) = UpdatePasswordRobot().apply { func() }
+class UpdatePasswordRobot : FormRobot() {
+
+ fun enterEmail(email: String) = fillEditText(R.id.email_update, email)
+ fun enterPassword(password: String) = fillEditText(R.id.password_top, password)
+ fun enterNewPassword(email: String) = fillEditText(R.id.password_bottom, email)
+ fun submitDelete() = clickButton(R.id.submit)
+
+ fun submitForm(email: String, password: String, newPassword: String) {
+ enterEmail(email)
+ enterPassword(password)
+ enterNewPassword(newPassword)
+ submit()
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/UpdateProfileRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/UpdateProfileRobot.kt
new file mode 100644
index 0000000..9e4e15a
--- /dev/null
+++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/UpdateProfileRobot.kt
@@ -0,0 +1,17 @@
+package h_mal.appttude.com.driver.robots
+
+import h_mal.appttude.com.driver.FormRobot
+import h_mal.appttude.com.driver.R
+
+fun updateProfile(func: UpdateProfileRobot.() -> Unit) = UpdateProfileRobot().apply { func() }
+class UpdateProfileRobot : FormRobot() {
+
+ fun enterName(name: String) = fillEditText(R.id.update_name, name)
+ fun selectImage() = selectSingleImage(R.id.profile_img, FilePath.PROFILE_PIC)
+
+ fun submitForm(name: String) {
+// selectImage()
+ enterName(name)
+ submit()
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/UpdateRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/UpdateRobot.kt
new file mode 100644
index 0000000..7ddd3fb
--- /dev/null
+++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/UpdateRobot.kt
@@ -0,0 +1,14 @@
+package h_mal.appttude.com.driver.robots
+
+import h_mal.appttude.com.driver.BaseTestRobot
+import h_mal.appttude.com.driver.R
+
+fun update(func: UpdateRobot.() -> Unit) = UpdateRobot().apply { func() }
+class UpdateRobot : BaseTestRobot() {
+
+ fun updateEmail() = clickButton(R.id.update_email_button)
+ fun updatePassword() = clickButton(R.id.update_password_button)
+ fun updateProfile() = clickButton(R.id.update_profile_button)
+ fun deleteProfile() = clickButton(R.id.delete_profile)
+
+}
\ No newline at end of file
diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/VehicleScreenRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/VehicleScreenRobot.kt
new file mode 100644
index 0000000..86ee1ba
--- /dev/null
+++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/VehicleScreenRobot.kt
@@ -0,0 +1,15 @@
+package h_mal.appttude.com.driver.robots
+
+import h_mal.appttude.com.driver.BaseTestRobot
+import h_mal.appttude.com.driver.R
+
+fun vehicleScreen(func: VehicleScreenRobot.() -> Unit) = VehicleScreenRobot().apply { func() }
+class VehicleScreenRobot : BaseTestRobot() {
+
+ fun vehicleProfile() = clickButton(R.id.vehicle_prof)
+ fun insurance() = clickButton(R.id.insurance)
+ fun mot() = clickButton(R.id.mot)
+ fun logbook() = clickButton(R.id.logbook)
+ fun privateHireVehicleLicense() = clickButton(R.id.private_hire_vehicle_license)
+
+}
\ No newline at end of file
diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/driver/DriversLicenseRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/driver/DriversLicenseRobot.kt
new file mode 100644
index 0000000..0c3270f
--- /dev/null
+++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/driver/DriversLicenseRobot.kt
@@ -0,0 +1,27 @@
+package h_mal.appttude.com.driver.robots.driver
+
+import h_mal.appttude.com.driver.FormRobot
+import h_mal.appttude.com.driver.R
+
+fun driversLicense(func: DriversLicenseRobot.() -> Unit) = DriversLicenseRobot().apply { func() }
+class DriversLicenseRobot : FormRobot() {
+
+ fun enterLicenseNumber(text: String) = fillEditText(R.id.lic_no, text)
+ fun enterLicenseExpiry(year: Int, monthOfYear: Int, dayOfMonth: Int) =
+ setDate(R.id.lic_expiry, year, monthOfYear, dayOfMonth)
+
+ fun selectImage() = selectSingleImage(R.id.search_image, FilePath.LICENSE)
+
+ fun submitForm(licenseNumber: String, year: Int, monthOfYear: Int, dayOfMonth: Int) {
+ selectImage()
+ enterLicenseNumber(licenseNumber)
+ enterLicenseExpiry(year, monthOfYear, dayOfMonth)
+ submit()
+ }
+
+ fun validate() {
+ checkImageViewHasImage(R.id.driversli_img)
+
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/driver/DriversProfileRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/driver/DriversProfileRobot.kt
new file mode 100644
index 0000000..da44a6a
--- /dev/null
+++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/driver/DriversProfileRobot.kt
@@ -0,0 +1,38 @@
+package h_mal.appttude.com.driver.robots.driver
+
+import h_mal.appttude.com.driver.FormRobot
+import h_mal.appttude.com.driver.R
+
+fun driversProfile(func: DriversProfileRobot.() -> Unit) = DriversProfileRobot().apply { func() }
+class DriversProfileRobot : FormRobot() {
+
+ fun enterName(name: String) = fillEditText(R.id.names_input, name)
+ fun enterAddress(address: String) = fillEditText(R.id.address_input, address)
+ fun enterPostcode(postcode: String) = fillEditText(R.id.postcode_input, postcode)
+ fun enterDateOfBirth(dob: String) = fillEditText(R.id.dob_input, dob)
+ fun enterNINumber(niNumber: String) = fillEditText(R.id.ni_number, niNumber)
+ fun enterDateFirstAvailable(year: Int, monthOfYear: Int, dayOfMonth: Int) =
+ setDate(R.id.date_first, year, monthOfYear, dayOfMonth)
+
+ fun selectImage() = selectSingleImage(R.id.add_photo, FilePath.PROFILE_PIC)
+
+ fun submitForm(
+ name: String,
+ address: String,
+ postcode: String,
+ dob: String,
+ niNumber: String,
+ year: Int,
+ monthOfYear: Int,
+ dayOfMonth: Int
+ ) {
+ selectImage()
+ enterName(name)
+ enterAddress(address)
+ enterPostcode(postcode)
+ enterDateOfBirth(dob)
+ enterNINumber(niNumber)
+ enterDateFirstAvailable(year, monthOfYear, dayOfMonth)
+ submit()
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/driver/PrivateHireLicenseRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/driver/PrivateHireLicenseRobot.kt
new file mode 100644
index 0000000..6f5c9d1
--- /dev/null
+++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/driver/PrivateHireLicenseRobot.kt
@@ -0,0 +1,23 @@
+package h_mal.appttude.com.driver.robots.driver
+
+import h_mal.appttude.com.driver.FormRobot
+import h_mal.appttude.com.driver.R
+
+fun privateHireLicenseRobot(func: PrivateHireLicenseRobot.() -> Unit) =
+ PrivateHireLicenseRobot().apply { func() }
+
+class PrivateHireLicenseRobot : FormRobot() {
+
+ fun enterLicenseNumber(text: String) = fillEditText(R.id.ph_no, text)
+ fun enterLicenseExpiry(year: Int, monthOfYear: Int, dayOfMonth: Int) =
+ setDate(R.id.ph_expiry, year, monthOfYear, dayOfMonth)
+
+ fun selectImage() = selectSingleImage(R.id.uploadphlic, FilePath.PRIVATE_HIRE)
+
+ fun submitForm(licenseNumber: String, year: Int, monthOfYear: Int, dayOfMonth: Int) {
+ selectImage()
+ enterLicenseNumber(licenseNumber)
+ enterLicenseExpiry(year, monthOfYear, dayOfMonth)
+ submit()
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/InsuranceRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/InsuranceRobot.kt
new file mode 100644
index 0000000..348e066
--- /dev/null
+++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/InsuranceRobot.kt
@@ -0,0 +1,23 @@
+package h_mal.appttude.com.driver.robots.vehicle
+
+import h_mal.appttude.com.driver.FormRobot
+import h_mal.appttude.com.driver.FormRobot.FilePath.Companion.getFilePath
+import h_mal.appttude.com.driver.R
+
+fun insurance(func: InsuranceRobot.() -> Unit) = InsuranceRobot().apply { func() }
+class InsuranceRobot : FormRobot() {
+
+ fun enterInsurance(text: String) = fillEditText(R.id.insurer, text)
+ fun enterInsuranceExpiry(year: Int, monthOfYear: Int, dayOfMonth: Int) =
+ setDate(R.id.insurance_exp, year, monthOfYear, dayOfMonth)
+
+ fun selectImages() =
+ selectMultipleImage(R.id.uploadInsurance, arrayOf(getFilePath(FilePath.INSURANCE)))
+
+ fun submitForm(insurer: String, year: Int, monthOfYear: Int, dayOfMonth: Int) {
+ selectImages()
+ enterInsurance(insurer)
+ enterInsuranceExpiry(year, monthOfYear, dayOfMonth)
+ submit()
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/LogbookRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/LogbookRobot.kt
new file mode 100644
index 0000000..33d69ad
--- /dev/null
+++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/LogbookRobot.kt
@@ -0,0 +1,18 @@
+package h_mal.appttude.com.driver.robots.vehicle
+
+import h_mal.appttude.com.driver.FormRobot
+import h_mal.appttude.com.driver.R
+
+fun logbook(func: LogbookRobot.() -> Unit) = LogbookRobot().apply { func() }
+class LogbookRobot : FormRobot() {
+
+ fun selectImages() = selectSingleImage(R.id.uploadmot, FilePath.MOT)
+ fun enterExpiryDate(year: Int, monthOfYear: Int, dayOfMonth: Int) =
+ setDate(R.id.mot_expiry, year, monthOfYear, dayOfMonth)
+
+ fun submitForm(year: Int, monthOfYear: Int, dayOfMonth: Int) {
+ selectImages()
+ enterExpiryDate(year, monthOfYear, dayOfMonth)
+ submit()
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/MOTRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/MOTRobot.kt
new file mode 100644
index 0000000..c6e1456
--- /dev/null
+++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/MOTRobot.kt
@@ -0,0 +1,17 @@
+package h_mal.appttude.com.driver.robots.vehicle
+
+import h_mal.appttude.com.driver.FormRobot
+import h_mal.appttude.com.driver.R
+
+fun mot(func: MOTRobot.() -> Unit) = MOTRobot().apply { func() }
+class MOTRobot : FormRobot() {
+
+ fun enterV5cNumber(v5c: String) = fillEditText(R.id.mot_expiry, v5c)
+ fun selectImages() = selectSingleImage(R.id.mot_expiry, FilePath.LOGBOOK)
+
+ fun submitForm(v5c: String) {
+ selectImages()
+ enterV5cNumber(v5c)
+ submit()
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/PrivateHireVehicleLicenseRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/PrivateHireVehicleLicenseRobot.kt
new file mode 100644
index 0000000..4dd7a81
--- /dev/null
+++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/PrivateHireVehicleLicenseRobot.kt
@@ -0,0 +1,23 @@
+package h_mal.appttude.com.driver.robots.vehicle
+
+import h_mal.appttude.com.driver.FormRobot
+import h_mal.appttude.com.driver.R
+
+fun privateHireVehicleLicense(func: PrivateHireVehicleLicenseRobot.() -> Unit) =
+ PrivateHireVehicleLicenseRobot().apply { func() }
+
+class PrivateHireVehicleLicenseRobot : FormRobot() {
+
+ fun enterLicenseNumber(text: String) = fillEditText(R.id.ph_no, text)
+ fun enterLicenseExpiry(year: Int, monthOfYear: Int, dayOfMonth: Int) =
+ setDate(R.id.ph_expiry, year, monthOfYear, dayOfMonth)
+
+ fun selectImage() = selectSingleImage(R.id.uploadphlic, FilePath.PRIVATE_HIRE)
+
+ fun submitForm(licenseNumber: String, year: Int, monthOfYear: Int, dayOfMonth: Int) {
+ selectImage()
+ enterLicenseNumber(licenseNumber)
+ enterLicenseExpiry(year, monthOfYear, dayOfMonth)
+ submit()
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/VehicleProfileRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/VehicleProfileRobot.kt
new file mode 100644
index 0000000..a168b4d
--- /dev/null
+++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/VehicleProfileRobot.kt
@@ -0,0 +1,46 @@
+package h_mal.appttude.com.driver.robots.vehicle
+
+import h_mal.appttude.com.driver.FormRobot
+import h_mal.appttude.com.driver.R
+import h_mal.appttude.com.driver.helpers.EspressoHelper.setChecked
+
+fun vehicleProfile(func: VehicleProfileRobot.() -> Unit) = VehicleProfileRobot().apply { func() }
+class VehicleProfileRobot : FormRobot() {
+
+ fun enterRegistration(reg: String) = fillEditText(R.id.reg, reg)
+ fun enterMake(make: String) = fillEditText(R.id.make, make)
+ fun enterModel(model: String) = fillEditText(R.id.car_model, model)
+ fun enterColour(colour: String) = fillEditText(R.id.colour, colour)
+ fun enterAddress(address: String) = fillEditText(R.id.address, address)
+ fun enterPostcode(postCode: String) = fillEditText(R.id.postcode, postCode)
+ fun enterKeeperName(name: String) = fillEditText(R.id.keeper_name, name)
+ fun enterDateFirstAvailable(year: Int, monthOfYear: Int, dayOfMonth: Int) =
+ setDate(R.id.start_date, year, monthOfYear, dayOfMonth)
+
+ fun isSeized(seized: Boolean) = matchView(R.id.seized_checkbox).perform(setChecked(seized))
+
+ fun submitForm(
+ reg: String,
+ make: String,
+ model: String,
+ colour: String,
+ address: String,
+ postCode: String,
+ name: String,
+ year: Int,
+ monthOfYear: Int,
+ dayOfMonth: Int,
+ seized: Boolean = false
+ ) {
+ enterRegistration(reg)
+ enterMake(make)
+ enterModel(model)
+ enterColour(colour)
+ enterAddress(address)
+ enterPostcode(postCode)
+ enterKeeperName(name)
+ enterDateFirstAvailable(year, monthOfYear, dayOfMonth)
+ isSeized(seized)
+ submit()
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/UserAuthenticationActivityTest.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/UserAuthenticationActivityTest.kt
index c2a995a..eb03bde 100644
--- a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/UserAuthenticationActivityTest.kt
+++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/UserAuthenticationActivityTest.kt
@@ -33,7 +33,10 @@ class UserAuthenticationActivityTest : FirebaseTest(LoginActivity
}
home {
checkTitleExists(getResourceString(R.string.welcome_title))
+ updateProfile()
}
+
+ // TODO: update user details
}
}
diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/SubmitNewDataActivityTest.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/SubmitNewDataActivityTest.kt
new file mode 100644
index 0000000..631a08c
--- /dev/null
+++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/SubmitNewDataActivityTest.kt
@@ -0,0 +1,37 @@
+package h_mal.appttude.com.driver.tests.newUser
+
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.test.rule.GrantPermissionRule
+import h_mal.appttude.com.driver.FirebaseTest
+import h_mal.appttude.com.driver.R
+import h_mal.appttude.com.driver.robots.*
+import h_mal.appttude.com.driver.robots.driver.driversLicense
+import h_mal.appttude.com.driver.ui.MainActivity
+import org.junit.*
+import org.junit.runner.RunWith
+
+
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+class SubmitNewDataActivityTest :
+ FirebaseTest(MainActivity::class.java, registered = true, signedIn = true) {
+
+ @Test
+ fun verifyUserRegistration_validUsernameAndPassword_loggedIn() {
+ home {
+ waitFor(2500)
+ checkTitleExists(getResourceString(R.string.welcome_title))
+ requestProfile()
+ openDriverProfile()
+ }
+ driverScreen {
+ driverLicense()
+ }
+ driversLicense {
+ submitForm("SAMPLE8456310LTU", 2022, 10, 2)
+ }
+ }
+
+}
diff --git a/app/src/debug/AndroidManifest.xml b/app/src/debug/AndroidManifest.xml
index 8451b0c..b30cb5f 100644
--- a/app/src/debug/AndroidManifest.xml
+++ b/app/src/debug/AndroidManifest.xml
@@ -1,6 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
10.0.2.2
diff --git a/app/src/driver/AndroidManifest.xml b/app/src/driver/AndroidManifest.xml
deleted file mode 100644
index 53dd8d6..0000000
--- a/app/src/driver/AndroidManifest.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/app/src/main/java/h_mal/appttude/com/driver/application/ApplicationViewModelFactory.kt b/app/src/driver/java/h_mal/appttude/com/driver/application/ApplicationViewModelFactory.kt
similarity index 97%
rename from app/src/main/java/h_mal/appttude/com/driver/application/ApplicationViewModelFactory.kt
rename to app/src/driver/java/h_mal/appttude/com/driver/application/ApplicationViewModelFactory.kt
index 224b355..0f81ab1 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/application/ApplicationViewModelFactory.kt
+++ b/app/src/driver/java/h_mal/appttude/com/driver/application/ApplicationViewModelFactory.kt
@@ -5,6 +5,7 @@ import androidx.lifecycle.ViewModelProvider
import h_mal.appttude.com.driver.data.FirebaseAuthSource
import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
import h_mal.appttude.com.driver.data.FirebaseStorageSource
+import h_mal.appttude.com.driver.data.prefs.PreferenceProvider
import h_mal.appttude.com.driver.viewmodels.*
class ApplicationViewModelFactory(
@@ -23,6 +24,11 @@ class ApplicationViewModelFactory(
auth,
storage
)
+ isAssignableFrom(RoleViewModel::class.java) -> RoleViewModel(
+ auth,
+ database,
+ storage
+ )
isAssignableFrom(DriverLicenseViewModel::class.java) -> DriverLicenseViewModel(
auth,
database,
@@ -59,11 +65,6 @@ class ApplicationViewModelFactory(
database,
storage
)
- isAssignableFrom(RoleViewModel::class.java) -> RoleViewModel(
- auth,
- database,
- storage
- )
else -> throw IllegalArgumentException("Unknown ViewModel class")
} as T
}
diff --git a/app/src/driver/java/h_mal/appttude/com/driver/application/DriverApplication.kt b/app/src/driver/java/h_mal/appttude/com/driver/application/DriverApplication.kt
new file mode 100644
index 0000000..855d97a
--- /dev/null
+++ b/app/src/driver/java/h_mal/appttude/com/driver/application/DriverApplication.kt
@@ -0,0 +1,28 @@
+package h_mal.appttude.com.driver.application
+
+import android.app.Application
+import android.content.res.Resources
+import h_mal.appttude.com.driver.data.FirebaseAuthSource
+import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
+import h_mal.appttude.com.driver.data.FirebaseStorageSource
+import h_mal.appttude.com.driver.data.prefs.PreferenceProvider
+import org.kodein.di.Kodein
+import org.kodein.di.KodeinAware
+import org.kodein.di.android.x.androidXModule
+import org.kodein.di.generic.bind
+import org.kodein.di.generic.instance
+import org.kodein.di.generic.provider
+import org.kodein.di.generic.singleton
+
+class DriverApplication : BaseApplication() {
+
+ override val flavourModule = super.flavourModule.copy {
+ bind() from provider {
+ ApplicationViewModelFactory(
+ instance(),
+ instance(),
+ instance()
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/driver/java/h_mal/appttude/com/driver/ui/MainActivity.kt b/app/src/driver/java/h_mal/appttude/com/driver/ui/MainActivity.kt
index 270d7ba..9f2eaf1 100644
--- a/app/src/driver/java/h_mal/appttude/com/driver/ui/MainActivity.kt
+++ b/app/src/driver/java/h_mal/appttude/com/driver/ui/MainActivity.kt
@@ -33,6 +33,7 @@ class MainActivity : DrawerActivity() {
setupDrawer(data)
}
}
+
}
private fun setupDrawer(user: FirebaseUser) {
diff --git a/app/src/driver/java/h_mal/appttude/com/driver/ui/driverprofile/DriverProfileFragment.kt b/app/src/driver/java/h_mal/appttude/com/driver/ui/driverprofile/DriverProfileFragment.kt
index 91b0022..9bf7614 100644
--- a/app/src/driver/java/h_mal/appttude/com/driver/ui/driverprofile/DriverProfileFragment.kt
+++ b/app/src/driver/java/h_mal/appttude/com/driver/ui/driverprofile/DriverProfileFragment.kt
@@ -37,7 +37,7 @@ class DriverProfileFragment :
}
}
addPhoto.setOnClickListener { openGalleryWithPermissionRequest() }
- submitDriver.setOnClickListener { submit() }
+ submit.setOnClickListener { submit() }
}
override fun submit() {
diff --git a/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/InsuranceFragment.kt b/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/InsuranceFragment.kt
index 2f304b1..535fd10 100644
--- a/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/InsuranceFragment.kt
+++ b/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/InsuranceFragment.kt
@@ -34,7 +34,7 @@ class InsuranceFragment :
}
}
uploadInsurance.setOnClickListener { openGalleryWithPermissionRequest() }
- submitIns.setOnClickListener { submit() }
+ submit.setOnClickListener { submit() }
}
}
diff --git a/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/LogbookFragment.kt b/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/LogbookFragment.kt
index fc37aa9..be5afe7 100644
--- a/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/LogbookFragment.kt
+++ b/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/LogbookFragment.kt
@@ -17,7 +17,7 @@ class LogbookFragment :
override fun setupView(binding: FragmentLogbookBinding) = binding.run {
v5cNo.setTextOnChange { model.v5cnumber = it }
uploadLb.setOnClickListener { openGalleryWithPermissionRequest() }
- submitLb.setOnClickListener { submit() }
+ submit.setOnClickListener { submit() }
}
override fun submit() {
diff --git a/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/MotFragment.kt b/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/MotFragment.kt
index 8aed6be..f129729 100644
--- a/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/MotFragment.kt
+++ b/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/MotFragment.kt
@@ -24,7 +24,7 @@ class MotFragment : DataSubmissionBaseFragment model.isSeized = res }
- submitVehicle.setOnClickListener {
+ submit.setOnClickListener {
validateEditTexts(
reg,
make,
diff --git a/app/src/main/java/h_mal/appttude/com/driver/viewmodels/DriverLicenseViewModel.kt b/app/src/driver/java/h_mal/appttude/com/driver/viewmodels/DriverLicenseViewModel.kt
similarity index 93%
rename from app/src/main/java/h_mal/appttude/com/driver/viewmodels/DriverLicenseViewModel.kt
rename to app/src/driver/java/h_mal/appttude/com/driver/viewmodels/DriverLicenseViewModel.kt
index 04dadfd..3df8d66 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/viewmodels/DriverLicenseViewModel.kt
+++ b/app/src/driver/java/h_mal/appttude/com/driver/viewmodels/DriverLicenseViewModel.kt
@@ -20,7 +20,7 @@ class DriverLicenseViewModel(
override val storageRef: StorageReference = storage.driversLicenseStorageRef(uid)
override val objectName: String = "drivers license"
- override fun getDataFromDatabase() = getDataClass()
+ override fun getDataFromDatabase() = retrieveDataFromDatabase()
override fun setDataInDatabase(data: DriversLicense, localImageUri: Uri?) = io {
doTryOperation("Failed to upload $objectName") {
diff --git a/app/src/main/java/h_mal/appttude/com/driver/viewmodels/DriverProfileViewModel.kt b/app/src/driver/java/h_mal/appttude/com/driver/viewmodels/DriverProfileViewModel.kt
similarity index 93%
rename from app/src/main/java/h_mal/appttude/com/driver/viewmodels/DriverProfileViewModel.kt
rename to app/src/driver/java/h_mal/appttude/com/driver/viewmodels/DriverProfileViewModel.kt
index ee6514c..e523c31 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/viewmodels/DriverProfileViewModel.kt
+++ b/app/src/driver/java/h_mal/appttude/com/driver/viewmodels/DriverProfileViewModel.kt
@@ -19,8 +19,7 @@ class DriverProfileViewModel(
override val databaseRef: DatabaseReference = database.getDriverDetailsRef(uid)
override val storageRef: StorageReference = storage.profileImageStorageRef(uid)
override val objectName: String = "drivers profile"
-
- override fun getDataFromDatabase() = getDataClass()
+ override fun getDataFromDatabase() = retrieveDataFromDatabase()
override fun setDataInDatabase(data: DriverProfile, localImageUri: Uri?) = io {
doTryOperation("Failed to upload $objectName") {
diff --git a/app/src/main/java/h_mal/appttude/com/driver/viewmodels/InsuranceViewModel.kt b/app/src/driver/java/h_mal/appttude/com/driver/viewmodels/InsuranceViewModel.kt
similarity index 95%
rename from app/src/main/java/h_mal/appttude/com/driver/viewmodels/InsuranceViewModel.kt
rename to app/src/driver/java/h_mal/appttude/com/driver/viewmodels/InsuranceViewModel.kt
index dff3c6c..328aeaf 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/viewmodels/InsuranceViewModel.kt
+++ b/app/src/driver/java/h_mal/appttude/com/driver/viewmodels/InsuranceViewModel.kt
@@ -20,7 +20,7 @@ class InsuranceViewModel(
override val storageRef: StorageReference = storage.insuranceStorageRef(uid)
override val objectName: String = "insurance"
- override fun getDataFromDatabase() = getDataClass()
+ override fun getDataFromDatabase() = retrieveDataFromDatabase()
override fun setDataInDatabase(data: Insurance, localImageUris: List?) = io {
doTryOperation("Failed to upload $objectName") {
diff --git a/app/src/main/java/h_mal/appttude/com/driver/viewmodels/LogbookViewModel.kt b/app/src/driver/java/h_mal/appttude/com/driver/viewmodels/LogbookViewModel.kt
similarity index 94%
rename from app/src/main/java/h_mal/appttude/com/driver/viewmodels/LogbookViewModel.kt
rename to app/src/driver/java/h_mal/appttude/com/driver/viewmodels/LogbookViewModel.kt
index 5f2dd43..0efcb1d 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/viewmodels/LogbookViewModel.kt
+++ b/app/src/driver/java/h_mal/appttude/com/driver/viewmodels/LogbookViewModel.kt
@@ -20,7 +20,7 @@ class LogbookViewModel(
override val storageRef: StorageReference = storage.logBookStorageRef(uid)
override val objectName: String = "Log book"
- override fun getDataFromDatabase() = getDataClass()
+ override fun getDataFromDatabase() = retrieveDataFromDatabase()
override fun setDataInDatabase(data: Logbook, localImageUri: Uri?) = io {
doTryOperation("Failed to upload $objectName") {
diff --git a/app/src/main/java/h_mal/appttude/com/driver/viewmodels/MotViewModel.kt b/app/src/driver/java/h_mal/appttude/com/driver/viewmodels/MotViewModel.kt
similarity index 94%
rename from app/src/main/java/h_mal/appttude/com/driver/viewmodels/MotViewModel.kt
rename to app/src/driver/java/h_mal/appttude/com/driver/viewmodels/MotViewModel.kt
index ac932af..3f06454 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/viewmodels/MotViewModel.kt
+++ b/app/src/driver/java/h_mal/appttude/com/driver/viewmodels/MotViewModel.kt
@@ -20,7 +20,7 @@ class MotViewModel(
override val storageRef: StorageReference? = storage.motStorageRef(uid)
override val objectName: String = "vehicle profile"
- override fun getDataFromDatabase() = getDataClass()
+ override fun getDataFromDatabase() = retrieveDataFromDatabase()
override fun setDataInDatabase(data: Mot, localImageUri: Uri?) = io {
doTryOperation("Failed to upload $objectName") {
diff --git a/app/src/main/java/h_mal/appttude/com/driver/viewmodels/PrivateHireLicenseViewModel.kt b/app/src/driver/java/h_mal/appttude/com/driver/viewmodels/PrivateHireLicenseViewModel.kt
similarity index 94%
rename from app/src/main/java/h_mal/appttude/com/driver/viewmodels/PrivateHireLicenseViewModel.kt
rename to app/src/driver/java/h_mal/appttude/com/driver/viewmodels/PrivateHireLicenseViewModel.kt
index 0f502b3..e234012 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/viewmodels/PrivateHireLicenseViewModel.kt
+++ b/app/src/driver/java/h_mal/appttude/com/driver/viewmodels/PrivateHireLicenseViewModel.kt
@@ -20,7 +20,7 @@ class PrivateHireLicenseViewModel(
override val storageRef: StorageReference = storage.privateHireStorageRef(uid)
override val objectName: String = "private hire license"
- override fun getDataFromDatabase() = getDataClass()
+ override fun getDataFromDatabase() = retrieveDataFromDatabase()
override fun setDataInDatabase(data: PrivateHireLicense, localImageUri: Uri?) = io {
doTryOperation("Failed to upload private hire license") {
diff --git a/app/src/main/java/h_mal/appttude/com/driver/viewmodels/PrivateHireVehicleViewModel.kt b/app/src/driver/java/h_mal/appttude/com/driver/viewmodels/PrivateHireVehicleViewModel.kt
similarity index 93%
rename from app/src/main/java/h_mal/appttude/com/driver/viewmodels/PrivateHireVehicleViewModel.kt
rename to app/src/driver/java/h_mal/appttude/com/driver/viewmodels/PrivateHireVehicleViewModel.kt
index e4bf9be..901d83a 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/viewmodels/PrivateHireVehicleViewModel.kt
+++ b/app/src/driver/java/h_mal/appttude/com/driver/viewmodels/PrivateHireVehicleViewModel.kt
@@ -20,7 +20,7 @@ class PrivateHireVehicleViewModel(
override val storageRef: StorageReference = storage.privateHireVehicleStorageRef(uid)
override val objectName: String = "private hire vehicle license"
- override fun getDataFromDatabase() = getDataClass()
+ override fun getDataFromDatabase() = retrieveDataFromDatabase()
override fun setDataInDatabase(data: PrivateHireVehicle, localImageUri: Uri?) = io {
doTryOperation("Failed to upload $objectName") {
diff --git a/app/src/main/java/h_mal/appttude/com/driver/viewmodels/VehicleProfileViewModel.kt b/app/src/driver/java/h_mal/appttude/com/driver/viewmodels/VehicleProfileViewModel.kt
similarity index 92%
rename from app/src/main/java/h_mal/appttude/com/driver/viewmodels/VehicleProfileViewModel.kt
rename to app/src/driver/java/h_mal/appttude/com/driver/viewmodels/VehicleProfileViewModel.kt
index 0be90ed8..143a935 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/viewmodels/VehicleProfileViewModel.kt
+++ b/app/src/driver/java/h_mal/appttude/com/driver/viewmodels/VehicleProfileViewModel.kt
@@ -19,7 +19,7 @@ class VehicleProfileViewModel(
override val storageRef: StorageReference? = null
override val objectName: String = "vehicle profile"
- override fun getDataFromDatabase() = getDataClass()
+ override fun getDataFromDatabase() = retrieveDataFromDatabase()
override fun setDataInDatabase(data: VehicleProfile) {
io {
diff --git a/app/src/driver/res/layout/activity_main.xml b/app/src/driver/res/layout/activity_main.xml
new file mode 100644
index 0000000..498e7f4
--- /dev/null
+++ b/app/src/driver/res/layout/activity_main.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/driver/res/layout/driver_profile_request.xml b/app/src/driver/res/layout/driver_profile_request.xml
new file mode 100644
index 0000000..4eb86e8
--- /dev/null
+++ b/app/src/driver/res/layout/driver_profile_request.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_driver_overall.xml b/app/src/driver/res/layout/fragment_driver_overall.xml
similarity index 100%
rename from app/src/main/res/layout/fragment_driver_overall.xml
rename to app/src/driver/res/layout/fragment_driver_overall.xml
diff --git a/app/src/main/res/layout/fragment_home_driver.xml b/app/src/driver/res/layout/fragment_home_driver.xml
similarity index 100%
rename from app/src/main/res/layout/fragment_home_driver.xml
rename to app/src/driver/res/layout/fragment_home_driver.xml
diff --git a/app/src/main/res/layout/fragment_vehicle_overall.xml b/app/src/driver/res/layout/fragment_vehicle_overall.xml
similarity index 100%
rename from app/src/main/res/layout/fragment_vehicle_overall.xml
rename to app/src/driver/res/layout/fragment_vehicle_overall.xml
diff --git a/app/src/driver/res/values/strings.xml b/app/src/driver/res/values/strings.xml
index 6048840..22e70ea 100644
--- a/app/src/driver/res/values/strings.xml
+++ b/app/src/driver/res/values/strings.xml
@@ -1,4 +1,3 @@
-
- Hello blank fragment
+ Driver Choice cars
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 2c36fa8..9c321a0 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -5,7 +5,7 @@
@@ -25,17 +24,16 @@
- private var dateArchivedText: TextView? = null
- override fun getCount(): Int {
- return size
- }
-
- override fun getItem(position: Int): Any? {
- when (archiveString) {
-// FirebaseClass.PRIVATE_HIRE_FIREBASE -> return archiveObject?.private_hire
-// ?.get(mKeys[position])
-// FirebaseClass.DRIVERS_LICENSE_FIREBASE -> return archiveObject?.driver_license
-// ?.get(mKeys[position])
-// FirebaseClass.VEHICLE_DETAILS_FIREBASE -> return archiveObject?.vehicle_details
-// ?.get(mKeys[position])
-// FirebaseClass.MOT_FIREBASE -> return archiveObject?.mot_details?.get(mKeys[position])
-// FirebaseClass.INSURANCE_FIREBASE -> return archiveObject?.insurance_details?.get(
-// mKeys[position]
-// )
-// FirebaseClass.LOG_BOOK_FIREBASE -> return archiveObject?.log_book
-// ?.get(mKeys.get(position))
-// FirebaseClass.PRIVATE_HIRE_VEHICLE_LICENSE -> return archiveObject?.ph_car?.get(mKeys[position])
- else -> return mKeys[position]
- }
- }
-
- override fun getItemId(position: Int): Long {
- return position.toLong()
- }
-
- override fun getView(position: Int, convertView: View, parent: ViewGroup): View {
- var listItemView: View = convertView
-//
-// if (listItemView == null) {
-// if (((archiveString == FirebaseClass.PRIVATE_HIRE_FIREBASE) || (archiveString == FirebaseClass.DRIVERS_LICENSE_FIREBASE) || (archiveString == FirebaseClass.MOT_FIREBASE) || (archiveString == FirebaseClass.LOG_BOOK_FIREBASE) || (archiveString == FirebaseClass.PRIVATE_HIRE_VEHICLE_LICENSE))) {
-// listItemView = LayoutInflater.from(context).inflate(
-// R.layout.archive_license_item, parent, false
-// )
-// val imageView: ImageView = listItemView.findViewById(R.id.image_archive)
-// dateArchivedText = listItemView.findViewById(R.id.date_archived)
-// val expiryHolder: LinearLayout = listItemView.findViewById(R.id.expiry_view)
-// val fieldTwo: LinearLayout = listItemView.findViewById(R.id.field_two_view)
-// val expiryText: TextView = listItemView.findViewById(R.id.exp_text)
-// val fiewTwoLable: TextView = listItemView.findViewById(R.id.field_two)
-// val fieldTwoText: TextView = listItemView.findViewById(R.id.field_two_text)
-// when (archiveString) {
-//// FirebaseClass.PRIVATE_HIRE_FIREBASE -> {
-//// expiryHolder.visibility = View.VISIBLE
-//// fieldTwo.visibility = View.VISIBLE
-//// val privateHireObject: PrivateHireObject =
-//// getItem(position) as PrivateHireObject
-//// Picasso.get().load(privateHireObject.phImageString)
-//// .placeholder(R.drawable.choice_img)
-//// .into(imageView)
-//// dateString(position)
-//// expiryText.text = privateHireObject.phExpiry
-//// fiewTwoLable.text = "Private Hire License No.:"
-//// fieldTwoText.text = privateHireObject.phNumber
-//// }
-//// FirebaseClass.DRIVERS_LICENSE_FIREBASE -> {
-//// expiryHolder.visibility = View.VISIBLE
-//// fieldTwo.visibility = View.VISIBLE
-//// val driversLicenseObject: DriversLicenseObject =
-//// getItem(position) as DriversLicenseObject
-//// Picasso.get().load(driversLicenseObject.licenseImageString)
-//// .placeholder(R.drawable.choice_img)
-//// .into(imageView)
-//// dateString(position)
-//// expiryText.text = driversLicenseObject.licenseExpiry
-//// fiewTwoLable.text = "License No.:"
-//// fieldTwoText.text = driversLicenseObject.licenseNumber
-//// }
-//// FirebaseClass.MOT_FIREBASE -> {
-//// expiryHolder.visibility = View.VISIBLE
-//// fieldTwo.visibility = View.GONE
-//// val motObject: MotObject = getItem(position) as MotObject
-//// Picasso.get().load(motObject.motImageString)
-//// .placeholder(R.drawable.choice_img)
-//// .into(imageView)
-//// dateString(position)
-//// expiryText.text = motObject.motExpiry
-//// }
-//// FirebaseClass.LOG_BOOK_FIREBASE -> {
-//// expiryHolder.visibility = View.GONE
-//// fieldTwo.visibility = View.VISIBLE
-//// val logbookObject: LogbookObject = getItem(position) as LogbookObject
-//// Picasso.get().load(logbookObject.photoString)
-//// .into(MainActivity.loadImage(imageView))
-//// dateString(position)
-//// fiewTwoLable.text = "V5C No.:"
-//// fieldTwoText.text = logbookObject.v5cnumber
-//// }
-//// FirebaseClass.PRIVATE_HIRE_VEHICLE_LICENSE -> {
-//// expiryHolder.visibility = View.VISIBLE
-//// fieldTwo.visibility = View.VISIBLE
-//// val privateHireVehicleObject: PrivateHireVehicleObject =
-//// getItem(position) as PrivateHireVehicleObject
-//// Picasso.get().load(privateHireVehicleObject.phCarImageString)
-//// .into(MainActivity.loadImage(imageView))
-//// dateString(position)
-//// expiryText.text = privateHireVehicleObject.phCarExpiry
-//// fiewTwoLable.text = "Private Hire Vehicle License No.:"
-//// fieldTwoText.text = privateHireVehicleObject.phCarNumber
-//// }
-//// }
-//// } else if ((archiveString == FirebaseClass.INSURANCE_FIREBASE)) {
-//// listItemView = LayoutInflater.from(context).inflate(
-//// R.layout.archive_insurance_item, parent, false
-//// )
-//// val holder: View = listItemView.findViewById(R.id.image_pager)
-//// val swiperClass: ImageSwiperClass = ImageSwiperClass(context, holder)
-//// // swiperClass.hideDelete();
-//// listItemView.findViewById(R.id.delete).visibility = View.GONE
-//// // holder.findViewById(R.id.delete).setVisibility(View.INVISIBLE);
-//// dateArchivedText = listItemView.findViewById(R.id.date_archived)
-//// dateString(position)
-//// val expiryText: TextView = listItemView.findViewById(R.id.exp_text)
-//// val fieldTwoText: TextView = listItemView.findViewById(R.id.archive_insurer)
-//// val insuranceObject: InsuranceObject = getItem(position) as InsuranceObject
-////// swiperClass.reinstantiateList(insuranceObject.photoStrings)
-//// expiryText.text = insuranceObject.expiryDate
-//// fieldTwoText.text = insuranceObject.insurerName
-//// } else if ((archiveString == FirebaseClass.VEHICLE_DETAILS_FIREBASE)) {
-//// listItemView = LayoutInflater.from(context).inflate(
-//// R.layout.archive_vehicle_item, parent, false
-//// )
-//// dateArchivedText = listItemView.findViewById(R.id.date_archived)
-//// dateString(position)
-//// val numberPlate: TextView = listItemView.findViewById(R.id.number_plate)
-//// val keeperName: TextView = listItemView.findViewById(R.id.keeper_name)
-//// val keeperAddress: TextView = listItemView.findViewById(R.id.keeper_address)
-//// val carText: TextView = listItemView.findViewById(R.id.car_text_arch)
-//// val carColour: TextView = listItemView.findViewById(R.id.car_colour)
-//// val carSeized: TextView = listItemView.findViewById(R.id.seized_checkbox)
-//// val startDate: TextView = listItemView.findViewById(R.id.first_date)
-//// val vehicleProfileObject: VehicleProfileObject =
-//// getItem(position) as VehicleProfileObject
-//// numberPlate.text = vehicleProfileObject.reg
-//// keeperName.text = vehicleProfileObject.keeperName
-//// keeperAddress.text = vehicleProfileObject.keeperAddress + "\n" + vehicleProfileObject.keeperPostCode
-//// carText.text = vehicleProfileObject.make + " " + vehicleProfileObject.model
-//// carColour.text = vehicleProfileObject.colour
-//// val s: String
-//// if (vehicleProfileObject.isSeized) {
-//// s = "Yes"
-//// } else {
-//// s = "No"
-//// }
-//// carSeized.text = s
-//// startDate.text = vehicleProfileObject.startDate
-//// }
-//// }
- return listItemView
- }
-
- private fun dateString(position: Int) {
- var success: Boolean = true
- try {
- dateArchivedText!!.text =
- mKeys[position].convertDateStringDatePattern("yyyyMMdd_HHmmss", "dd/MM/yyyy")
- } catch (e: ParseException) {
- e.printStackTrace()
- success = false
- } finally {
- if (!success) {
- dateArchivedText!!.text = mKeys.get(position).substring(0, 8)
- }
- }
- }
-
- companion object {
- private val TAG: String = "ArchiveObjectListAdapte"
- }
-
-// init {
-// archiveObject?.apply {
-// val map = when (archiveString) {
-// FirebaseClass.PRIVATE_HIRE_FIREBASE -> private_hire
-// FirebaseClass.DRIVERS_LICENSE_FIREBASE -> driver_license
-// FirebaseClass.VEHICLE_DETAILS_FIREBASE -> vehicle_details
-// FirebaseClass.MOT_FIREBASE -> mot_details
-// FirebaseClass.INSURANCE_FIREBASE -> insurance_details
-// FirebaseClass.LOG_BOOK_FIREBASE -> log_book
-// FirebaseClass.PRIVATE_HIRE_VEHICLE_LICENSE -> ph_car
-// else -> null
-// }
-// setUp(map)
-// }
-//
-// }
-
- private fun setUp(map: HashMap?) {
- size = map?.size ?: 0
- map?.keys?.toTypedArray()?.let {
- mKeys = it
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/h_mal/appttude/com/driver/base/BaseActivity.kt b/app/src/main/java/h_mal/appttude/com/driver/base/BaseActivity.kt
index 0cef4bd..c20577e 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/base/BaseActivity.kt
+++ b/app/src/main/java/h_mal/appttude/com/driver/base/BaseActivity.kt
@@ -1,29 +1,36 @@
package h_mal.appttude.com.driver.base
import android.content.Intent
+import android.os.Build
import android.os.Bundle
-import android.view.LayoutInflater
import android.view.View
+import android.view.View.OnAttachStateChangeListener
import android.view.ViewGroup.LayoutParams
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.inflate
+import android.widget.Toast
import androidx.annotation.VisibleForTesting
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelLazy
import androidx.test.espresso.IdlingResource
import androidx.viewbinding.ViewBinding
+import com.google.android.material.snackbar.BaseTransientBottomBar.BaseCallback
+import com.google.android.material.snackbar.Snackbar
import h_mal.appttude.com.driver.R
import h_mal.appttude.com.driver.application.ApplicationViewModelFactory
import h_mal.appttude.com.driver.data.ViewState
-import h_mal.appttude.com.driver.utils.*
+import h_mal.appttude.com.driver.utils.BasicIdlingResource
+import h_mal.appttude.com.driver.utils.GenericsHelper.getGenericClassAt
+import h_mal.appttude.com.driver.utils.GenericsHelper.inflateBindingByType
+import h_mal.appttude.com.driver.utils.hide
+import h_mal.appttude.com.driver.utils.show
+import h_mal.appttude.com.driver.utils.triggerAnimation
import org.kodein.di.KodeinAware
import org.kodein.di.android.kodein
import org.kodein.di.generic.instance
-import java.lang.reflect.ParameterizedType
-import kotlin.reflect.KClass
-
-abstract class BaseActivity : AppCompatActivity(), KodeinAware {
+abstract class BaseActivity : AppCompatActivity(),
+ KodeinAware {
// The Idling Resource which will be null in production.
private var mIdlingResource: BasicIdlingResource? = null
private lateinit var loadingView: View
@@ -47,34 +54,10 @@ abstract class BaseActivity : AppCompatActi
{ defaultViewModelCreationExtras }
)
- @Suppress("UNCHECKED_CAST")
- fun Any.getGenericClassAt(position: Int): KClass =
- ((javaClass.genericSuperclass as? ParameterizedType)
- ?.actualTypeArguments?.getOrNull(position) as? Class)
- ?.kotlin
- ?: throw IllegalStateException("Can not find class from generic argument")
-
- /**
- * Create a view binding out of the the generic [VB]
- */
- private fun inflateBindingByType(
- genericClassAt: KClass
- ): VB = try {
- @Suppress("UNCHECKED_CAST")
- genericClassAt.java.methods.first { viewBinding ->
- viewBinding.parameterTypes.size == 1
- && viewBinding.parameterTypes.getOrNull(0) == LayoutInflater::class.java
- }.invoke(null, layoutInflater) as VB
- } catch (exception: Exception) {
- throw IllegalStateException("Can not inflate binding from generic")
- }
-
- private var loading: Boolean = false
-
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
configureObserver()
- _binding = inflateBindingByType(getGenericClassAt(1))
+ _binding = inflateBindingByType(getGenericClassAt(1), layoutInflater)
setContentView(requireNotNull(_binding).root)
setupView(binding)
}
@@ -119,7 +102,6 @@ abstract class BaseActivity : AppCompatActi
*/
open fun onStarted() {
loadingView.fadeIn()
- loading = true
mIdlingResource?.setIdleState(false)
}
@@ -128,7 +110,6 @@ abstract class BaseActivity : AppCompatActi
*/
open fun onSuccess(data: Any?) {
loadingView.fadeOut()
- loading = false
mIdlingResource?.setIdleState(true)
}
@@ -136,9 +117,8 @@ abstract class BaseActivity : AppCompatActi
* Called in case of failure or some error emitted from the liveData in viewModel
*/
open fun onFailure(error: String?) {
- error?.let { displayToast(it) }
+ error?.let { showToast(it) }
loadingView.fadeOut()
- loading = false
mIdlingResource?.setIdleState(true)
}
@@ -164,7 +144,46 @@ abstract class BaseActivity : AppCompatActi
override fun onBackPressed() {
- if (!loading) super.onBackPressed()
+ loadingView.hide()
+ super.onBackPressed()
+ }
+
+ fun showToast(message: String) {
+ val toast = Toast.makeText(this, message, Toast.LENGTH_LONG)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ toast.addCallback(object : Toast.Callback() {
+ override fun onToastHidden() {
+ super.onToastHidden()
+ mIdlingResource?.setIdleState(true)
+ }
+ override fun onToastShown() {
+ super.onToastShown()
+ mIdlingResource?.setIdleState(false)
+ }
+ })
+ } else {
+
+ }
+ toast.show()
+ }
+
+ fun showSnackBar(message: String) {
+ val snackbar = Snackbar.make(
+ window.decorView.findViewById(android.R.id.content),
+ message,
+ Snackbar.LENGTH_LONG
+ )
+ snackbar.addCallback(object : BaseCallback() {
+ override fun onShown(transientBottomBar: Snackbar?) {
+ super.onShown(transientBottomBar)
+ mIdlingResource?.setIdleState(false)
+ }
+ override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
+ super.onDismissed(transientBottomBar, event)
+ mIdlingResource?.setIdleState(true)
+ }
+ })
+ snackbar.show()
}
/**
diff --git a/app/src/main/java/h_mal/appttude/com/driver/base/BaseFirebaseAdapter.kt b/app/src/main/java/h_mal/appttude/com/driver/base/BaseFirebaseAdapter.kt
new file mode 100644
index 0000000..62b13c5
--- /dev/null
+++ b/app/src/main/java/h_mal/appttude/com/driver/base/BaseFirebaseAdapter.kt
@@ -0,0 +1,80 @@
+package h_mal.appttude.com.driver.base
+
+import android.net.ConnectivityManager
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import androidx.recyclerview.widget.RecyclerView.ViewHolder
+import androidx.viewbinding.ViewBinding
+import com.firebase.ui.database.FirebaseRecyclerAdapter
+import com.firebase.ui.database.FirebaseRecyclerOptions
+import com.google.firebase.database.DatabaseError
+import h_mal.appttude.com.driver.utils.GenericsHelper.getGenericClassAt
+import h_mal.appttude.com.driver.utils.GenericsHelper.inflateBindingByType
+import java.nio.ByteBuffer
+
+
+open class BaseFirebaseAdapter(
+ options: FirebaseRecyclerOptions,
+ private val layoutInflater: LayoutInflater
+) :
+ FirebaseRecyclerAdapter>(options) {
+
+ private val connectivityManager =
+ layoutInflater.context.getSystemService(ConnectivityManager::class.java) as ConnectivityManager
+
+ private var _binding: VB? = null
+ val binding: VB
+ get() = _binding ?: error("Must only access binding while fragment is attached.")
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder {
+ _binding = inflateBindingByType(getGenericClassAt(1), layoutInflater)
+ val lp = RecyclerView.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ binding.root.layoutParams = lp
+ return CustomViewHolder(requireNotNull(_binding))
+ }
+
+ override fun onBindViewHolder(holder: CustomViewHolder, position: Int, model: T) {}
+
+ override fun getItemId(position: Int): Long {
+ return snapshots.getSnapshot(position).key?.toByteArray()
+ ?.let { ByteBuffer.wrap(it).long } ?: super.getItemId(position)
+ }
+
+ fun getKeyAtPosition(position: Int) = snapshots.getSnapshot(position).key
+
+ override fun startListening() {
+ super.startListening()
+ // check if network is connected
+ if (connectivityManager.activeNetwork == null) {
+ connectionLost()
+ }
+ }
+
+ open fun connectionLost() {}
+ override fun onDataChanged() {
+ super.onDataChanged()
+ if (itemCount == 0) emptyList()
+ }
+ override fun onError(error: DatabaseError) {
+ super.onError(error)
+ when (error.code) {
+ DatabaseError.PERMISSION_DENIED -> permissionsDenied()
+ DatabaseError.DISCONNECTED, DatabaseError.UNAVAILABLE, DatabaseError.NETWORK_ERROR -> noConnection()
+ DatabaseError.EXPIRED_TOKEN, DatabaseError.OPERATION_FAILED, DatabaseError.INVALID_TOKEN, DatabaseError.MAX_RETRIES -> authorizationError()
+ else -> cannotRetrieve()
+ }
+
+ }
+
+ open fun permissionsDenied() {}
+ open fun noConnection() {}
+ open fun cannotRetrieve() {}
+ open fun authorizationError() {}
+ open fun emptyList() {}
+}
+
+class CustomViewHolder(val viewBinding: VB) : ViewHolder(viewBinding.root)
\ No newline at end of file
diff --git a/app/src/main/java/h_mal/appttude/com/driver/base/BaseFragment.kt b/app/src/main/java/h_mal/appttude/com/driver/base/BaseFragment.kt
index 25e769b..e80b26e 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/base/BaseFragment.kt
+++ b/app/src/main/java/h_mal/appttude/com/driver/base/BaseFragment.kt
@@ -1,29 +1,27 @@
package h_mal.appttude.com.driver.base
-import android.app.Activity
import android.content.ClipData
+import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import androidx.activity.result.contract.ActivityResultContract
import androidx.fragment.app.Fragment
import androidx.fragment.app.createViewModelLazy
import androidx.viewbinding.ViewBinding
import h_mal.appttude.com.driver.application.ApplicationViewModelFactory
import h_mal.appttude.com.driver.data.ViewState
+import h_mal.appttude.com.driver.utils.GenericsHelper.getGenericClassAt
+import h_mal.appttude.com.driver.utils.GenericsHelper.inflateBindingByType
import h_mal.appttude.com.driver.utils.PermissionsUtils
import org.kodein.di.KodeinAware
import org.kodein.di.android.x.kodein
import org.kodein.di.generic.instance
-import java.lang.reflect.ParameterizedType
-import kotlin.reflect.KClass
-const val IMAGE_SELECT_REQUEST_CODE = 401
-
-abstract class BaseFragment(
-) : Fragment(), KodeinAware {
+abstract class BaseFragment : Fragment(), KodeinAware {
private var _binding: VB? = null
private val binding: VB
@@ -31,7 +29,12 @@ abstract class BaseFragment(
var mActivity: BaseActivity? = null
+ override val kodein by kodein()
+ private val factory by instance()
+
val viewModel: V by getFragmentViewModel()
+ private fun getFragmentViewModel(): Lazy =
+ createViewModelLazy(getGenericClassAt(0), { viewModelStore }, factoryProducer = { factory })
private var multipleImage: Boolean = false
@@ -39,34 +42,6 @@ abstract class BaseFragment(
multipleImage = true
}
- override val kodein by kodein()
- val factory by instance()
-
- fun getFragmentViewModel(): Lazy =
- createViewModelLazy(getGenericClassAt(0), { viewModelStore }, factoryProducer = { factory })
-
- fun LayoutInflater.inflateBindingByType(
- container: ViewGroup?,
- genericClassAt: KClass
- ): VB = try {
- @Suppress("UNCHECKED_CAST")
- genericClassAt.java.methods.first { inflateFun ->
- inflateFun.parameterTypes.size == 3
- && inflateFun.parameterTypes.getOrNull(0) == LayoutInflater::class.java
- && inflateFun.parameterTypes.getOrNull(1) == ViewGroup::class.java
- && inflateFun.parameterTypes.getOrNull(2) == Boolean::class.java
- }.invoke(null, this, container, false) as VB
- } catch (exception: Exception) {
- throw IllegalStateException("Can not inflate binding from generic")
- }
-
- @Suppress("UNCHECKED_CAST")
- fun Any.getGenericClassAt(position: Int): KClass =
- ((javaClass.genericSuperclass as? ParameterizedType)
- ?.actualTypeArguments?.getOrNull(position) as? Class)
- ?.kotlin
- ?: throw IllegalStateException("Can not find class from generic argument")
-
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -126,25 +101,6 @@ abstract class BaseFragment(
}
}
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- super.onActivityResult(requestCode, resultCode, data)
- if (resultCode == Activity.RESULT_OK) {
- when (requestCode) {
- IMAGE_SELECT_REQUEST_CODE -> {
- data?.clipData?.convertToList()?.let { clip ->
- val list = clip.takeIf { it.size > 10 }?.let {
- clip.subList(0, 9)
- } ?: clip
- onImageGalleryResult(list)
- return
- }
- onImageGalleryResult(data?.data)
- }
- }
-
- }
- }
-
private fun ClipData.convertToList(): List = 0.rangeTo(itemCount).map { getItemAt(it).uri }
/**
@@ -180,10 +136,38 @@ abstract class BaseFragment(
open fun onImageGalleryResult(imageUris: List?) {}
fun openGalleryForImage() {
- val intent = Intent(Intent.ACTION_PICK)
- intent.type = "image/*"
- intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, multipleImage)
- startActivityForResult(intent, IMAGE_SELECT_REQUEST_CODE)
+ permissionRequest.launch(multipleImage)
}
+ private val permissionRequest = registerForActivityResult(getResultsContract()) { result ->
+ @Suppress("UNCHECKED_CAST")
+ when (result) {
+ is Uri -> onImageGalleryResult(result)
+ is List<*> -> onImageGalleryResult(result as List)
+ }
+ }
+
+ private fun getResultsContract(): ActivityResultContract {
+ return object : ActivityResultContract() {
+ override fun createIntent(context: Context, input: Boolean): Intent {
+ return Intent(Intent.ACTION_GET_CONTENT)
+ .addCategory(Intent.CATEGORY_OPENABLE)
+ .putExtra(Intent.EXTRA_ALLOW_MULTIPLE, input)
+ .setType("image/*")
+ }
+
+ override fun parseResult(resultCode: Int, intent: Intent?): Any? {
+ intent?.clipData?.takeIf { it.itemCount > 1 }?.convertToList()?.let { clip ->
+ val list = clip.takeIf { it.size > 10 }?.let {
+ clip.subList(0, 9)
+ } ?: clip
+ return list
+ }
+ return intent?.data
+ }
+ }
+ }
+
+ fun showToast(message: String) = (activity as BaseActivity<*, *>).showToast(message)
+ fun showSnackBar(message: String) = (activity as BaseActivity<*, *>).showSnackBar(message)
}
\ No newline at end of file
diff --git a/app/src/main/java/h_mal/appttude/com/driver/base/BaseViewModel.kt b/app/src/main/java/h_mal/appttude/com/driver/base/BaseViewModel.kt
index e94fe99..f32a029 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/base/BaseViewModel.kt
+++ b/app/src/main/java/h_mal/appttude/com/driver/base/BaseViewModel.kt
@@ -20,6 +20,9 @@ abstract class BaseViewModel : ViewModel() {
uiState.postValue(ViewState.HasError(Event(error)))
}
+ /*
+ * All in one function for trying an operation and handling its start and failure
+ */
suspend fun doTryOperation(
defaultErrorMessage: String?,
operation: suspend () -> Unit
@@ -29,14 +32,11 @@ abstract class BaseViewModel : ViewModel() {
operation()
} catch (e: Exception) {
e.printStackTrace()
- e.message?.let {
- onError(it)
- return
- }
defaultErrorMessage?.let {
onError(it)
return
}
+ onError((e.message ?: "Operation failed!!"))
}
}
}
\ No newline at end of file
diff --git a/app/src/main/java/h_mal/appttude/com/driver/base/DataSubmissionBaseViewModel.kt b/app/src/main/java/h_mal/appttude/com/driver/base/DataSubmissionBaseViewModel.kt
index 5e3793c..d962e18 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/base/DataSubmissionBaseViewModel.kt
+++ b/app/src/main/java/h_mal/appttude/com/driver/base/DataSubmissionBaseViewModel.kt
@@ -15,6 +15,7 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import java.io.IOException
+
abstract class DataSubmissionBaseViewModel(
auth: FirebaseAuthentication,
private val database: FirebaseDatabaseSource,
@@ -32,7 +33,7 @@ abstract class DataSubmissionBaseViewModel(
open fun setDataInDatabase(data: T, localImageUris: List?): Job = Job()
open fun setDataInDatabase(data: T) {}
- inline fun getDataClass() = io {
+ inline fun retrieveDataFromDatabase() = io {
doTryOperation("Failed to retrieve $objectName") {
val data = databaseRef.getDataFromDatabaseRef()
onSuccess(data ?: FirebaseCompletion.Default)
diff --git a/app/src/main/java/h_mal/appttude/com/driver/base/DrawerActivity.kt b/app/src/main/java/h_mal/appttude/com/driver/base/DrawerActivity.kt
index ef12248..22194a2 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/base/DrawerActivity.kt
+++ b/app/src/main/java/h_mal/appttude/com/driver/base/DrawerActivity.kt
@@ -48,7 +48,6 @@ abstract class DrawerActivity : BaseActivit
appBarConfiguration = AppBarConfiguration(navController.graph, drawerLayout)
navView.setupWithNavController(navController)
setupActionBarWithNavController(navController, appBarConfiguration)
-
}
override fun onSupportNavigateUp(): Boolean {
diff --git a/app/src/main/java/h_mal/appttude/com/driver/data/FirebaseAuthSource.kt b/app/src/main/java/h_mal/appttude/com/driver/data/FirebaseAuthSource.kt
index 8820572..dec0995 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/data/FirebaseAuthSource.kt
+++ b/app/src/main/java/h_mal/appttude/com/driver/data/FirebaseAuthSource.kt
@@ -2,7 +2,11 @@ package h_mal.appttude.com.driver.data
import android.net.Uri
import com.google.android.gms.tasks.Task
-import com.google.firebase.auth.*
+import com.google.firebase.auth.AuthResult
+import com.google.firebase.auth.EmailAuthProvider
+import com.google.firebase.auth.FirebaseAuth
+import com.google.firebase.auth.FirebaseUser
+import com.google.firebase.auth.UserProfileChangeRequest
import java.io.IOException
class FirebaseAuthSource : FirebaseAuthentication {
diff --git a/app/src/main/java/h_mal/appttude/com/driver/data/FirebaseDatabaseSource.kt b/app/src/main/java/h_mal/appttude/com/driver/data/FirebaseDatabaseSource.kt
index 9b798d2..adbeee4 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/data/FirebaseDatabaseSource.kt
+++ b/app/src/main/java/h_mal/appttude/com/driver/data/FirebaseDatabaseSource.kt
@@ -21,6 +21,7 @@ const val PRIVATE_HIRE_VEHICLE = "private_hire_vehicle"
const val VEHICLE_DETAILS = "vehicle_details"
const val ARCHIVE = "archive"
+@SuppressWarnings("unused|WeakerAccess")
class FirebaseDatabaseSource {
private val database = FirebaseDatabase.getInstance()
@@ -35,11 +36,17 @@ class FirebaseDatabaseSource {
return data
}
- fun getUserRef(uid: String) = database.getReference(USER_CONST).child(uid)
+ fun getDatabaseRefFromPath(path: String) = database.getReference(path)
+
+ val users = database.getReference(USER_CONST)
+
+ fun getUsersRef() = database.reference.child(USER_CONST)
+ fun getUserRef(uid: String) = users.child(uid)
fun getUserDetailsRef(uid: String) = getUserRef(uid).child(USER_DETAILS)
fun getVehicleRef(uid: String) = getUserRef(uid).child(VEHICLE_PROFILE)
fun getDriverRef(uid: String) = getUserRef(uid).child(DRIVER_PROFILE)
fun getApprovalsRef(uid: String) = getUserRef(uid).child(APPROVALS)
+ fun getDocumentApprovalRef(uid: String, document: String) = getApprovalsRef(uid).child(document)
fun getArchiveRef(uid: String) = getUserRef(uid).child(ARCHIVE)
fun getUserRoleRef(uid: String) = getUserRef(uid).child(PROFILE_ROLE)
fun getDriverNumberRef(uid: String) = getUserRef(uid).child(DRIVER_NUMBER)
diff --git a/app/src/main/java/h_mal/appttude/com/driver/data/Roles.kt b/app/src/main/java/h_mal/appttude/com/driver/data/Roles.kt
index 4231fee..3dd629e 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/data/Roles.kt
+++ b/app/src/main/java/h_mal/appttude/com/driver/data/Roles.kt
@@ -1,4 +1,4 @@
package h_mal.appttude.com.driver.data
const val DRIVER = "driver"
-const val ADMIN = "super_user"
\ No newline at end of file
+const val ADMIN = "admin"
\ No newline at end of file
diff --git a/app/src/main/java/h_mal/appttude/com/driver/data/prefs/PreferencesProvider.kt b/app/src/main/java/h_mal/appttude/com/driver/data/prefs/PreferencesProvider.kt
new file mode 100644
index 0000000..b017b28
--- /dev/null
+++ b/app/src/main/java/h_mal/appttude/com/driver/data/prefs/PreferencesProvider.kt
@@ -0,0 +1,29 @@
+package h_mal.appttude.com.driver.data.prefs
+
+import android.content.Context
+import android.content.SharedPreferences
+import androidx.preference.PreferenceManager
+
+/**
+ * Shared prefs class used for storing conversion name values as pairs
+ * Then retrieving as pairs
+ *
+ */
+const val SORT_OPTION = "SORT_OPTION"
+class PreferenceProvider (context: Context) {
+
+ private val appContext = context.applicationContext
+
+ private val preference: SharedPreferences =
+ PreferenceManager.getDefaultSharedPreferences(appContext)
+
+ fun setSortOption(sortLabel: String) {
+ preference.edit()
+ .putString(SORT_OPTION, sortLabel)
+ .apply()
+ }
+
+ fun getSortOption(): String? = preference
+ .getString(SORT_OPTION, null)
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/h_mal/appttude/com/driver/ui/update/DeleteProfileFragment.kt b/app/src/main/java/h_mal/appttude/com/driver/ui/update/DeleteProfileFragment.kt
index 1402ff2..2015bf7 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/ui/update/DeleteProfileFragment.kt
+++ b/app/src/main/java/h_mal/appttude/com/driver/ui/update/DeleteProfileFragment.kt
@@ -12,7 +12,7 @@ class DeleteProfileFragment :
override fun setupView(binding: FragmentDeleteProfileBinding) = binding.run {
passwordTop.setEnterPressedListener { deleteUser() }
- submissionButtonLabel.setOnClickListener { deleteUser() }
+ submit.setOnClickListener { deleteUser() }
}
private fun deleteUser() = applyBinding {
diff --git a/app/src/main/java/h_mal/appttude/com/driver/ui/update/UpdateActivity.kt b/app/src/main/java/h_mal/appttude/com/driver/ui/update/UpdateActivity.kt
index 71d6691..ea00689 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/ui/update/UpdateActivity.kt
+++ b/app/src/main/java/h_mal/appttude/com/driver/ui/update/UpdateActivity.kt
@@ -3,7 +3,6 @@ package h_mal.appttude.com.driver.ui.update
import h_mal.appttude.com.driver.base.BaseActivity
import h_mal.appttude.com.driver.data.FirebaseCompletion
import h_mal.appttude.com.driver.databinding.UpdateActivityBinding
-import h_mal.appttude.com.driver.utils.displayToast
import h_mal.appttude.com.driver.viewmodels.UpdateUserViewModel
class UpdateActivity : BaseActivity() {
@@ -11,7 +10,7 @@ class UpdateActivity : BaseActivity(
override fun onSuccess(data: Any?) {
super.onSuccess(data)
when (data) {
- is FirebaseCompletion.Changed -> displayToast(data.message)
+ is FirebaseCompletion.Changed -> showToast(data.message)
}
}
}
\ No newline at end of file
diff --git a/app/src/main/java/h_mal/appttude/com/driver/ui/update/UpdateEmailFragment.kt b/app/src/main/java/h_mal/appttude/com/driver/ui/update/UpdateEmailFragment.kt
index c0e1ef2..fe7e051 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/ui/update/UpdateEmailFragment.kt
+++ b/app/src/main/java/h_mal/appttude/com/driver/ui/update/UpdateEmailFragment.kt
@@ -12,7 +12,7 @@ class UpdateEmailFragment : BaseFragment Context.createIntent(): Intent =
- Intent(this, T::class.java)
-
- inline fun Fragment.createIntent() =
- requireContext().createIntent()
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/h_mal/appttude/com/driver/utils/DateUtils.kt b/app/src/main/java/h_mal/appttude/com/driver/utils/DateUtils.kt
index ed2d5bd..c8fef1f 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/utils/DateUtils.kt
+++ b/app/src/main/java/h_mal/appttude/com/driver/utils/DateUtils.kt
@@ -6,10 +6,6 @@ import java.text.SimpleDateFormat
import java.util.*
object DateUtils {
- fun getDateStamp(): String {
- val sdf: SimpleDateFormat = getSimpleDateFormat("yyyyMMdd_HHmm")
- return sdf.format(Date())
- }
fun getDateTimeStamp(): String {
val sdf: SimpleDateFormat = getSimpleDateFormat("yyyyMMdd_HHmmss")
@@ -21,7 +17,7 @@ object DateUtils {
return try {
val sdfIn = getSimpleDateFormat(formatIn)
val sdfOut = getSimpleDateFormat(formatOut)
- val newDate: Date = sdfIn.parse(this)
+ val newDate = sdfIn.parse(this)
sdfOut.format(newDate)
} catch (e: Exception) {
e.printStackTrace()
diff --git a/app/src/main/java/h_mal/appttude/com/driver/utils/Extensions.kt b/app/src/main/java/h_mal/appttude/com/driver/utils/Extensions.kt
index d509275..fbd64b5 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/utils/Extensions.kt
+++ b/app/src/main/java/h_mal/appttude/com/driver/utils/Extensions.kt
@@ -1,13 +1,22 @@
package h_mal.appttude.com.driver.utils
-
+/**
+ * Extension function that will execute high order if value is true or do nothing
+ *
+ * @sample #boolean.isTrue{ #Do something when its true }
+ */
inline fun Boolean.isTrue(block: () -> Unit){
if (this) {
block()
}
}
-inline fun T.isNotNull(block: (T) -> R): R?{
+/**
+ * Extension function that will execute high order if value is not null or do nothing
+ *
+ * @sample #nullable.isNotNull{i -> i.doSomethingSinceItsNotNull() }
+ */
+inline fun T?.isNotNull(block: (T) -> R): R?{
return if (this != null) {
block(this)
} else {
diff --git a/app/src/main/java/h_mal/appttude/com/driver/utils/FirebaseException.kt b/app/src/main/java/h_mal/appttude/com/driver/utils/FirebaseException.kt
new file mode 100644
index 0000000..5949f2a
--- /dev/null
+++ b/app/src/main/java/h_mal/appttude/com/driver/utils/FirebaseException.kt
@@ -0,0 +1,55 @@
+package h_mal.appttude.com.driver.utils
+
+import com.google.firebase.database.DatabaseError
+
+class FirebaseException(
+ private val databaseError: DatabaseError
+) : RuntimeException(databaseError.message, databaseError.toException()) {
+
+ fun getCode() = databaseError.code
+ fun getDetails() = databaseError.details
+
+ fun getErrorStatus(): Status {
+ return Status.getByScore(getCode()) ?: Status.UNKNOWN_ERROR
+ }
+
+ enum class Status(private val code: Int) {
+ DATA_STALE(-1),
+ /** The server indicated that this operation failed */
+ OPERATION_FAILED(-2),
+ /** This client does not have permission to perform this operation */
+ PERMISSION_DENIED(-3),
+ /** The operation had to be aborted due to a network disconnect */
+ DISCONNECTED(-4),
+ /** The supplied auth token has expired */
+ EXPIRED_TOKEN (-6),
+ /**
+ * The specified authentication token is invalid. This can occur when the token is malformed,
+ * expired, or the secret that was used to generate it has been revoked.
+ */
+ INVALID_TOKEN(-7),
+ /** The transaction had too many retries */
+ MAX_RETRIES(-8),
+ /** The transaction was overridden by a subsequent set */
+ OVERRIDDEN_BY_SET(-9),
+ /** The service is unavailable */
+ UNAVAILABLE(-10),
+ /** An exception occurred in user code */
+ USER_CODE_EXCEPTION(-11),
+ /** The operation could not be performed due to a network error. */
+ NETWORK_ERROR(-24),
+ /** The write was canceled locally */
+ WRITE_CANCELED(-25),
+ /**
+ * An unknown error occurred. Please refer to the error message and error details for more
+ * information.
+ */
+ UNKNOWN_ERROR(-999);
+
+ companion object {
+ infix fun getByScore(value: Int): Status? =
+ Status.values().firstOrNull { it.code == value }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/h_mal/appttude/com/driver/utils/FirebaseUtils.kt b/app/src/main/java/h_mal/appttude/com/driver/utils/FirebaseUtils.kt
index 98d7b9a..00b35bf 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/utils/FirebaseUtils.kt
+++ b/app/src/main/java/h_mal/appttude/com/driver/utils/FirebaseUtils.kt
@@ -30,7 +30,6 @@ suspend fun DatabaseReference.singleValueEvent(): EventResponse = suspendCorouti
/**
* Read database reference once {@link #DatabaseReference.addListenerForSingleValueEvent}
*
- *
* @return T
*/
suspend inline fun DatabaseReference.getDataFromDatabaseRef(): T? {
@@ -39,7 +38,34 @@ suspend inline fun DatabaseReference.getDataFromDatabaseRef():
response.snapshot.getValue(T::class.java)
}
is EventResponse.Cancelled -> {
- throw response.error.toException()
+ throw FirebaseException(response.error)
+ }
+ }
+}
+
+/**
+ * Read database reference once {@link #DatabaseReference.addListenerForSingleValueEvent}
+ *
+ * @return T
+ */
+suspend inline fun DatabaseReference.getListDataFromDatabaseRef(): List {
+ return when (val response: EventResponse = singleValueEvent()) {
+ is EventResponse.Changed -> {
+ response.snapshot.children.map { it.getValue(T::class.java) }
+ }
+ is EventResponse.Cancelled -> {
+ throw FirebaseException(response.error)
+ }
+ }
+}
+
+suspend fun DatabaseReference.getDataFromDatabaseRef(clazz : Class): T? {
+ return when (val response: EventResponse = singleValueEvent()) {
+ is EventResponse.Changed -> {
+ response.snapshot.getValue(clazz)
+ }
+ is EventResponse.Cancelled -> {
+ throw FirebaseException(response.error)
}
}
}
\ No newline at end of file
diff --git a/app/src/main/java/h_mal/appttude/com/driver/utils/GenericsHelper.kt b/app/src/main/java/h_mal/appttude/com/driver/utils/GenericsHelper.kt
new file mode 100644
index 0000000..24238dd
--- /dev/null
+++ b/app/src/main/java/h_mal/appttude/com/driver/utils/GenericsHelper.kt
@@ -0,0 +1,52 @@
+package h_mal.appttude.com.driver.utils
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.viewbinding.ViewBinding
+import java.lang.reflect.ParameterizedType
+import kotlin.reflect.KClass
+
+object GenericsHelper {
+ @Suppress("UNCHECKED_CAST")
+ fun Any.getGenericClassAt(position: Int): KClass =
+ ((javaClass.genericSuperclass as? ParameterizedType)
+ ?.actualTypeArguments?.getOrNull(position) as? Class)
+ ?.kotlin
+ ?: throw IllegalStateException("Can not find class from generic argument")
+
+ /**
+ * Create a view binding out of the the generic [VB]
+ *
+ * @sample inflateBindingByType(getGenericClassAt(0), layoutInflater)
+ */
+ fun inflateBindingByType(
+ genericClassAt: KClass,
+ layoutInflater: LayoutInflater
+ ): VB = try {
+ @Suppress("UNCHECKED_CAST")
+
+ genericClassAt.java.methods.first { viewBinding ->
+ viewBinding.parameterTypes.size == 1
+ && viewBinding.parameterTypes.getOrNull(0) == LayoutInflater::class.java
+ }.invoke(null, layoutInflater) as VB
+ } catch (exception: Exception) {
+ println ("generic class failed at = $genericClassAt")
+ exception.printStackTrace()
+ throw IllegalStateException("Can not inflate binding from generic")
+ }
+
+ fun LayoutInflater.inflateBindingByType(
+ container: ViewGroup?,
+ genericClassAt: KClass
+ ): VB = try {
+ @Suppress("UNCHECKED_CAST")
+ genericClassAt.java.methods.first { inflateFun ->
+ inflateFun.parameterTypes.size == 3
+ && inflateFun.parameterTypes.getOrNull(0) == LayoutInflater::class.java
+ && inflateFun.parameterTypes.getOrNull(1) == ViewGroup::class.java
+ && inflateFun.parameterTypes.getOrNull(2) == Boolean::class.java
+ }.invoke(null, this, container, false) as VB
+ } catch (exception: Exception) {
+ throw IllegalStateException("Can not inflate binding from generic")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/h_mal/appttude/com/driver/utils/NavigationUtils.kt b/app/src/main/java/h_mal/appttude/com/driver/utils/NavigationUtils.kt
index c48adf2..1108246 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/utils/NavigationUtils.kt
+++ b/app/src/main/java/h_mal/appttude/com/driver/utils/NavigationUtils.kt
@@ -1,28 +1,29 @@
package h_mal.appttude.com.driver.utils
-import android.content.Context
-import android.content.Intent
+import android.os.Bundle
+import android.os.Parcelable
import android.view.View
import androidx.annotation.IdRes
import androidx.navigation.Navigation
-const val UPLOAD_NEW = "upload_new"
+fun View.navigateTo(@IdRes navId: Int, args: Bundle? = null) {
+ Navigation
+ .findNavController(this)
+ .navigate(navId, args)
+}
+
+fun Any.toBundle(key: String): Bundle {
+ return Bundle().apply {
+ when (this@toBundle) {
+ is String -> putString(key, this@toBundle)
+ is Int -> putInt(key, this@toBundle)
+ is Boolean -> putBoolean(key, this@toBundle)
+ is Parcelable -> putParcelable(key, this@toBundle)
+ is Double -> putDouble(key, this@toBundle)
+ is Float -> putFloat(key, this@toBundle)
+ }
-fun navigateToActivity(context: Context, navigationActivity: Navigations) {
- try {
- val ourClass: Class<*> =
- Class.forName("h_mal.appttude.com.driver." + navigationActivity.value)
- val intent = Intent(context, ourClass)
- context.startActivity(intent)
- } catch (e: Exception) {
- e.printStackTrace()
}
}
-fun View.navigateTo(@IdRes navId: Int) {
- Navigation
- .findNavController(this)
- .navigate(navId)
-}
-
diff --git a/app/src/main/java/h_mal/appttude/com/driver/utils/ViewUtils.kt b/app/src/main/java/h_mal/appttude/com/driver/utils/ViewUtils.kt
index febf32d..ed50c3d 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/utils/ViewUtils.kt
+++ b/app/src/main/java/h_mal/appttude/com/driver/utils/ViewUtils.kt
@@ -2,7 +2,6 @@ package h_mal.appttude.com.driver.utils
import android.annotation.SuppressLint
import android.app.Activity
-import android.content.Context
import android.content.Intent
import android.content.res.Resources
import android.graphics.Bitmap
@@ -16,7 +15,6 @@ import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.ImageView
import android.widget.TextView
-import android.widget.Toast
import androidx.annotation.DrawableRes
import androidx.appcompat.widget.SearchView
import androidx.fragment.app.Fragment
@@ -33,14 +31,6 @@ fun View.hide() {
this.visibility = View.GONE
}
-fun Context.displayToast(message: String) {
- Toast.makeText(this, message, Toast.LENGTH_LONG).show()
-}
-
-fun Fragment.displayToast(message: String) {
- requireContext().displayToast(message)
-}
-
fun EditText.setEnterPressedListener(action: () -> Unit) {
setOnEditorActionListener(TextView.OnEditorActionListener { _, id, _ ->
if (id == EditorInfo.IME_ACTION_DONE || id == EditorInfo.IME_NULL) {
diff --git a/app/src/main/java/h_mal/appttude/com/driver/viewmodels/RoleViewModel.kt b/app/src/main/java/h_mal/appttude/com/driver/viewmodels/RoleViewModel.kt
index 3e3f6df..c0ea4ac 100644
--- a/app/src/main/java/h_mal/appttude/com/driver/viewmodels/RoleViewModel.kt
+++ b/app/src/main/java/h_mal/appttude/com/driver/viewmodels/RoleViewModel.kt
@@ -18,7 +18,7 @@ class RoleViewModel(
override val storageRef: StorageReference? = null
override val objectName: String = "role"
- override fun getDataFromDatabase() = getDataClass()
+ override fun getDataFromDatabase() = retrieveDataFromDatabase()
override fun setDataInDatabase(data: String) {
io {
diff --git a/app/src/main/res/drawable-hdpi/cars.png b/app/src/main/res/drawable-hdpi/cars.png
deleted file mode 100644
index f45e424..0000000
Binary files a/app/src/main/res/drawable-hdpi/cars.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/splash_screen.png b/app/src/main/res/drawable-hdpi/splash_screen.png
new file mode 100644
index 0000000..f707bb5
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/splash_screen.png differ
diff --git a/app/src/main/res/drawable-ldpi/cars.png b/app/src/main/res/drawable-ldpi/cars.png
deleted file mode 100644
index b0b31c7..0000000
Binary files a/app/src/main/res/drawable-ldpi/cars.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/cars.png b/app/src/main/res/drawable-mdpi/cars.png
deleted file mode 100644
index c863164..0000000
Binary files a/app/src/main/res/drawable-mdpi/cars.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/splash_screen.png b/app/src/main/res/drawable-mdpi/splash_screen.png
new file mode 100644
index 0000000..01c44b4
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/splash_screen.png differ
diff --git a/app/src/main/res/drawable-xhdpi/cars.png b/app/src/main/res/drawable-xhdpi/cars.png
deleted file mode 100644
index fc40c5e..0000000
Binary files a/app/src/main/res/drawable-xhdpi/cars.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/splash_screen.png b/app/src/main/res/drawable-xhdpi/splash_screen.png
new file mode 100644
index 0000000..4abd07a
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/splash_screen.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/bg.jpg b/app/src/main/res/drawable-xxhdpi/bg.jpg
deleted file mode 100644
index 3477474..0000000
Binary files a/app/src/main/res/drawable-xxhdpi/bg.jpg and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/cars.png b/app/src/main/res/drawable-xxhdpi/cars.png
deleted file mode 100644
index 248c230..0000000
Binary files a/app/src/main/res/drawable-xxhdpi/cars.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/splash_screen.png b/app/src/main/res/drawable-xxhdpi/splash_screen.png
new file mode 100644
index 0000000..a80cb6e
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/splash_screen.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/cars.png b/app/src/main/res/drawable-xxxhdpi/cars.png
deleted file mode 100644
index bdd868f..0000000
Binary files a/app/src/main/res/drawable-xxxhdpi/cars.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/splash_screen.png b/app/src/main/res/drawable-xxxhdpi/splash_screen.png
new file mode 100644
index 0000000..fe8defc
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/splash_screen.png differ
diff --git a/app/src/main/res/drawable/baseline_check_24.xml b/app/src/main/res/drawable/baseline_check_24.xml
new file mode 100644
index 0000000..2501e9f
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_check_24.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/baseline_clear_24.xml b/app/src/main/res/drawable/baseline_clear_24.xml
new file mode 100644
index 0000000..70db409
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_clear_24.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/baseline_inbox_24.xml b/app/src/main/res/drawable/baseline_inbox_24.xml
new file mode 100644
index 0000000..5857b5d
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_inbox_24.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/cardviewoutline.xml b/app/src/main/res/drawable/cardviewoutline.xml
deleted file mode 100644
index 9cdbe25..0000000
--- a/app/src/main/res/drawable/cardviewoutline.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/round_edit_text.xml b/app/src/main/res/drawable/round_edit_text.xml
deleted file mode 100644
index 744ceb1..0000000
--- a/app/src/main/res/drawable/round_edit_text.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/side_nav_bar.xml b/app/src/main/res/drawable/side_nav_bar.xml
deleted file mode 100644
index a36d7a1..0000000
--- a/app/src/main/res/drawable/side_nav_bar.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/zero.png b/app/src/main/res/drawable/zero.png
deleted file mode 100644
index ceadf26..0000000
Binary files a/app/src/main/res/drawable/zero.png and /dev/null differ
diff --git a/app/src/main/res/layout/address_dialog.xml b/app/src/main/res/layout/address_dialog.xml
deleted file mode 100644
index 39974a2..0000000
--- a/app/src/main/res/layout/address_dialog.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/archive_insurance_item.xml b/app/src/main/res/layout/archive_insurance_item.xml
deleted file mode 100644
index 64e7595..0000000
--- a/app/src/main/res/layout/archive_insurance_item.xml
+++ /dev/null
@@ -1,92 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/archive_vehicle_item.xml b/app/src/main/res/layout/archive_vehicle_item.xml
deleted file mode 100644
index ac0da39..0000000
--- a/app/src/main/res/layout/archive_vehicle_item.xml
+++ /dev/null
@@ -1,221 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/carousal_image_cell.xml b/app/src/main/res/layout/carousal_image_cell.xml
deleted file mode 100644
index e4024d0..0000000
--- a/app/src/main/res/layout/carousal_image_cell.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/driver_profile_request.xml b/app/src/main/res/layout/driver_profile_request.xml
deleted file mode 100644
index ad3ff8d..0000000
--- a/app/src/main/res/layout/driver_profile_request.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_archive.xml b/app/src/main/res/layout/fragment_archive.xml
deleted file mode 100644
index eb32c6e..0000000
--- a/app/src/main/res/layout/fragment_archive.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_delete_profile.xml b/app/src/main/res/layout/fragment_delete_profile.xml
index d8d07ee..8ee0da9 100644
--- a/app/src/main/res/layout/fragment_delete_profile.xml
+++ b/app/src/main/res/layout/fragment_delete_profile.xml
@@ -22,12 +22,12 @@
style="@style/subheader"
android:layout_marginBottom="24dp"
android:text="@string/delete_profile_subtitle"
- app:layout_constraintBottom_toTopOf="@id/til_old_email"
+ app:layout_constraintBottom_toTopOf="@id/til_name"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
+ app:layout_constraintTop_toBottomOf="@+id/til_name">
-
+
diff --git a/app/src/main/res/layout/fragment_image_viewer.xml b/app/src/main/res/layout/fragment_image_viewer.xml
index c5e989b..1da0898 100644
--- a/app/src/main/res/layout/fragment_image_viewer.xml
+++ b/app/src/main/res/layout/fragment_image_viewer.xml
@@ -10,7 +10,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000"
- tools:src="@drawable/cars" />
+ tools:src="@drawable/splash_screen" />
-
+ xmlns:app="http://schemas.android.com/apk/res-auto">
@@ -48,7 +49,8 @@
style="@style/EditTextStyle"
android:hint="@string/private_hire_license_no"
android:importantForAutofill="no"
- tools:ignore="TextFields" />
+ tools:ignore="TextFields"
+ tools:text="987651"/>
@@ -63,7 +65,8 @@
android:id="@+id/ph_expiry"
style="@style/EditTextStyle.Date"
android:hint="@string/private_hire_license_expiry"
- android:autofillHints="date" />
+ android:autofillHints="date"
+ tools:text="30/12/2018"/>
@@ -76,6 +79,6 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/til_submission"
app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintVertical_bias="0.8" />
+ app:layout_constraintVertical_bias="0.8"/>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_private_hire_vehicle.xml b/app/src/main/res/layout/fragment_private_hire_vehicle.xml
index 0a931cd..921a962 100644
--- a/app/src/main/res/layout/fragment_private_hire_vehicle.xml
+++ b/app/src/main/res/layout/fragment_private_hire_vehicle.xml
@@ -2,8 +2,7 @@
+ style="@style/parent_constraint_layout">
-
+ app:layout_constraintTop_toBottomOf="@id/til_new_password"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintVertical_bias="0.8" />
+
+
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintStart_toStartOf="parent" />
+ app:layout_constraintBottom_toTopOf="@id/til_email">
+ android:autofillHints="name"/>
-
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/til_name">
-
-
+ app:layout_constraintTop_toBottomOf="@+id/til_new_password">
-
-
-
-
-
diff --git a/app/src/main/res/layout/fragment_update_email.xml b/app/src/main/res/layout/fragment_update_email.xml
index 55153aa..9c57b47 100644
--- a/app/src/main/res/layout/fragment_update_email.xml
+++ b/app/src/main/res/layout/fragment_update_email.xml
@@ -23,14 +23,14 @@
android:text="@string/update_email_subtitle"
style="@style/subheader"
android:layout_marginBottom="24dp"
- app:layout_constraintBottom_toTopOf="@id/til_old_email"
+ app:layout_constraintBottom_toTopOf="@id/til_name"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="parent" />
+ tools:context="ui.update.UpdatePasswordFragment">
+ app:layout_constraintTop_toBottomOf="@+id/til_name">
+ tools:context=".ui.update.UpdateProfileFragment">
+ android:orientation="vertical">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/nav_header_main.xml b/app/src/main/res/layout/nav_header_main.xml
index 3002cf8..e33c493 100644
--- a/app/src/main/res/layout/nav_header_main.xml
+++ b/app/src/main/res/layout/nav_header_main.xml
@@ -11,7 +11,8 @@
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
- android:theme="@style/ThemeOverlay.AppCompat.Dark">
+ android:theme="@style/ThemeOverlay.AppCompat.Dark"
+ tools:ignore="Overdraw">
+ android:layout_height="match_parent">
+ android:layout_height="match_parent">
+ app:layout_constraintStart_toStartOf="parent" />
+ android:title="@string/sort"
+ app:showAsAction="ifRoom" />
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/drawable-hdpi/welcome_background.png b/app/src/main/res/mipmap-hdpi/drawable-hdpi/welcome_background.png
deleted file mode 100644
index 847c1e3..0000000
Binary files a/app/src/main/res/mipmap-hdpi/drawable-hdpi/welcome_background.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-hdpi/drawable-ldpi/welcome_background.png b/app/src/main/res/mipmap-hdpi/drawable-ldpi/welcome_background.png
deleted file mode 100644
index 20445c6..0000000
Binary files a/app/src/main/res/mipmap-hdpi/drawable-ldpi/welcome_background.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-hdpi/drawable-mdpi/welcome_background.png b/app/src/main/res/mipmap-hdpi/drawable-mdpi/welcome_background.png
deleted file mode 100644
index 910c85f..0000000
Binary files a/app/src/main/res/mipmap-hdpi/drawable-mdpi/welcome_background.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-hdpi/drawable-xhdpi/welcome_background.png b/app/src/main/res/mipmap-hdpi/drawable-xhdpi/welcome_background.png
deleted file mode 100644
index f269958..0000000
Binary files a/app/src/main/res/mipmap-hdpi/drawable-xhdpi/welcome_background.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-hdpi/drawable-xxhdpi/welcome_background.png b/app/src/main/res/mipmap-hdpi/drawable-xxhdpi/welcome_background.png
deleted file mode 100644
index fd5cc30..0000000
Binary files a/app/src/main/res/mipmap-hdpi/drawable-xxhdpi/welcome_background.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-hdpi/drawable-xxxhdpi/welcome_background.png b/app/src/main/res/mipmap-hdpi/drawable-xxxhdpi/welcome_background.png
deleted file mode 100644
index 3316f35..0000000
Binary files a/app/src/main/res/mipmap-hdpi/drawable-xxxhdpi/welcome_background.png and /dev/null differ
diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml
deleted file mode 100644
index fd7a058..0000000
--- a/app/src/main/res/values-v21/styles.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-