mirror of
https://github.com/hmalik144/Driver.git
synced 2025-12-10 02:45:20 +00:00
Release 29072023
This commit is contained in:
@@ -7,8 +7,104 @@ 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.
|
# 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/
|
# See: https://circleci.com/docs/2.0/orb-intro/
|
||||||
orbs:
|
orbs:
|
||||||
android: circleci/android@1.0.3
|
android: circleci/android@2.3.0
|
||||||
|
|
||||||
|
commands:
|
||||||
|
setup_repo:
|
||||||
|
description: checkout repo and android dependencies
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- run:
|
||||||
|
name: Setup subtree for test data
|
||||||
|
command: |
|
||||||
|
git config --global user.email "$GIT_EMAIL"
|
||||||
|
git config --global user.name "$GIT_EMAIL"
|
||||||
|
git subtree add --prefix=driver_app_data https://github.com/hmalik144/driver_app_data main
|
||||||
|
- android/restore-gradle-cache
|
||||||
|
- run:
|
||||||
|
name: Download Dependencies
|
||||||
|
command: |
|
||||||
|
sudo chmod +x ./gradlew
|
||||||
|
./gradlew androidDependencies
|
||||||
|
# Setup files for build.
|
||||||
|
- run:
|
||||||
|
name: Setup variables for build
|
||||||
|
command: |
|
||||||
|
echo "$GOOGLE_SERVICES_KEY" > "app/google-services.json"
|
||||||
|
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
|
||||||
|
- 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
|
||||||
|
- 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
|
||||||
# Define a job to be invoked later in a workflow.
|
# Define a job to be invoked later in a workflow.
|
||||||
# See: https://circleci.com/docs/2.0/configuration-reference/#jobs
|
# See: https://circleci.com/docs/2.0/configuration-reference/#jobs
|
||||||
jobs:
|
jobs:
|
||||||
@@ -23,76 +119,16 @@ jobs:
|
|||||||
# See: https://circleci.com/docs/2.0/executor-types/
|
# See: https://circleci.com/docs/2.0/executor-types/
|
||||||
executor:
|
executor:
|
||||||
name: android/android-machine
|
name: android/android-machine
|
||||||
|
tag: 2023.05.1
|
||||||
# Add steps to the job
|
# Add steps to the job
|
||||||
# See: https://circleci.com/docs/2.0/configuration-reference/#steps
|
# See: https://circleci.com/docs/2.0/configuration-reference/#steps
|
||||||
steps:
|
steps:
|
||||||
# Checkout the code as the first step.
|
# Checkout the code and its submodule as the first step.
|
||||||
- checkout
|
- setup_repo
|
||||||
# Setup files for build.
|
- run_tests:
|
||||||
- run:
|
flavour: << parameters.flavour >>
|
||||||
name: Setup variables for build
|
- run_ui_tests:
|
||||||
command: |
|
flavour: << parameters.flavour >>
|
||||||
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
|
|
||||||
parameters:
|
|
||||||
flavour:
|
|
||||||
type: string
|
|
||||||
default: ""
|
|
||||||
executor:
|
|
||||||
name: android/android-machine
|
|
||||||
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
|
|
||||||
# Invoke jobs via workflows
|
# Invoke jobs via workflows
|
||||||
# See: https://circleci.com/docs/2.0/configuration-reference/#workflows
|
# See: https://circleci.com/docs/2.0/configuration-reference/#workflows
|
||||||
workflows:
|
workflows:
|
||||||
@@ -100,23 +136,30 @@ workflows:
|
|||||||
build-release-driver:
|
build-release-driver:
|
||||||
jobs:
|
jobs:
|
||||||
- build-and-test:
|
- build-and-test:
|
||||||
flavour: Driver
|
|
||||||
- assemble-and-release:
|
|
||||||
flavour: "Driver"
|
flavour: "Driver"
|
||||||
|
- android/deploy-to-play-store:
|
||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
- main_driver
|
- main_driver
|
||||||
requires:
|
requires:
|
||||||
- build-and-test
|
- build-and-test
|
||||||
|
executor:
|
||||||
|
name: android/android-machine
|
||||||
|
tag: 2023.05.1
|
||||||
|
lane-name: deployDriver
|
||||||
build-release-admin:
|
build-release-admin:
|
||||||
jobs:
|
jobs:
|
||||||
- build-and-test:
|
- build-and-test:
|
||||||
flavour: Admin
|
flavour: "Admin"
|
||||||
- assemble-and-release:
|
- android/deploy-to-play-store:
|
||||||
flavour: Admin
|
|
||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
only: main_admin
|
only:
|
||||||
|
- main_driver
|
||||||
requires:
|
requires:
|
||||||
- build-and-test
|
- build-and-test
|
||||||
|
executor:
|
||||||
|
name: android/android-machine
|
||||||
|
tag: 2023.05.1
|
||||||
|
lane-name: deployAdmin
|
||||||
12
.gitignore
vendored
12
.gitignore
vendored
@@ -9,9 +9,21 @@
|
|||||||
/.idea/navEditor.xml
|
/.idea/navEditor.xml
|
||||||
/.idea/misc.xml
|
/.idea/misc.xml
|
||||||
/.idea/assetWizardSettings.xml
|
/.idea/assetWizardSettings.xml
|
||||||
|
/.idea/shelf/
|
||||||
.DS_Store
|
.DS_Store
|
||||||
/build
|
/build
|
||||||
/captures
|
/captures
|
||||||
.externalNativeBuild
|
.externalNativeBuild
|
||||||
*.log
|
*.log
|
||||||
local
|
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
|
||||||
|
|||||||
6
.idea/compiler.xml
generated
6
.idea/compiler.xml
generated
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="CompilerConfiguration">
|
|
||||||
<bytecodeTargetLevel target="17" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
7
.idea/dictionaries/h_mal.xml
generated
7
.idea/dictionaries/h_mal.xml
generated
@@ -1,7 +0,0 @@
|
|||||||
<component name="ProjectDictionaryState">
|
|
||||||
<dictionary name="h_mal">
|
|
||||||
<words>
|
|
||||||
<w>viewmodel</w>
|
|
||||||
</words>
|
|
||||||
</dictionary>
|
|
||||||
</component>
|
|
||||||
20
.idea/gradle.xml
generated
20
.idea/gradle.xml
generated
@@ -1,20 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
|
||||||
<component name="GradleSettings">
|
|
||||||
<option name="linkedExternalProjectsSettings">
|
|
||||||
<GradleProjectSettings>
|
|
||||||
<option name="testRunner" value="GRADLE" />
|
|
||||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
|
||||||
<option name="gradleJvm" value="Android Studio java home" />
|
|
||||||
<option name="modules">
|
|
||||||
<set>
|
|
||||||
<option value="$PROJECT_DIR$" />
|
|
||||||
<option value="$PROJECT_DIR$/app" />
|
|
||||||
</set>
|
|
||||||
</option>
|
|
||||||
</GradleProjectSettings>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
48
.idea/misc.xml
generated
48
.idea/misc.xml
generated
@@ -1,48 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="NullableNotNullManager">
|
|
||||||
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
|
|
||||||
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
|
|
||||||
<option name="myNullables">
|
|
||||||
<value>
|
|
||||||
<list size="12">
|
|
||||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
|
|
||||||
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
|
|
||||||
<item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
|
|
||||||
<item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
|
|
||||||
<item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
|
|
||||||
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
|
|
||||||
<item index="6" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
|
|
||||||
<item index="7" class="java.lang.String" itemvalue="android.annotation.Nullable" />
|
|
||||||
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
|
|
||||||
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
|
|
||||||
<item index="10" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
|
|
||||||
<item index="11" class="java.lang.String" itemvalue="com.android.annotations.Nullable" />
|
|
||||||
</list>
|
|
||||||
</value>
|
|
||||||
</option>
|
|
||||||
<option name="myNotNulls">
|
|
||||||
<value>
|
|
||||||
<list size="11">
|
|
||||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
|
|
||||||
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
|
|
||||||
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
|
|
||||||
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
|
|
||||||
<item index="4" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
|
|
||||||
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
|
|
||||||
<item index="6" class="java.lang.String" itemvalue="android.annotation.NonNull" />
|
|
||||||
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
|
|
||||||
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
|
|
||||||
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
|
|
||||||
<item index="10" class="java.lang.String" itemvalue="com.android.annotations.NonNull" />
|
|
||||||
</list>
|
|
||||||
</value>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17_PREVIEW" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
|
||||||
</component>
|
|
||||||
<component name="ProjectType">
|
|
||||||
<option name="id" value="Android" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@@ -9,7 +9,6 @@ plugins {
|
|||||||
def relStorePassword = System.getenv("RELEASE_STORE_PASSWORD")
|
def relStorePassword = System.getenv("RELEASE_STORE_PASSWORD")
|
||||||
def relKeyPassword = System.getenv("RELEASE_KEY_PASSWORD")
|
def relKeyPassword = System.getenv("RELEASE_KEY_PASSWORD")
|
||||||
def relKeyAlias = System.getenv("RELEASE_KEY_ALIAS")
|
def relKeyAlias = System.getenv("RELEASE_KEY_ALIAS")
|
||||||
def relStoreFile = System.getenv("RELEASE_KEYSTORE")
|
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 31
|
compileSdkVersion 31
|
||||||
@@ -17,8 +16,8 @@ android {
|
|||||||
applicationId "h_mal.appttude.com.driver"
|
applicationId "h_mal.appttude.com.driver"
|
||||||
minSdkVersion 24
|
minSdkVersion 24
|
||||||
targetSdkVersion 31
|
targetSdkVersion 31
|
||||||
versionCode 6
|
versionCode 7
|
||||||
versionName "1.6"
|
versionName "2.0.0"
|
||||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||||
|
|
||||||
boolean state = project.rootProject.file('local.properties').canRead()
|
boolean state = project.rootProject.file('local.properties').canRead()
|
||||||
@@ -41,7 +40,7 @@ android {
|
|||||||
storePassword relStorePassword
|
storePassword relStorePassword
|
||||||
keyPassword relKeyPassword
|
keyPassword relKeyPassword
|
||||||
keyAlias relKeyAlias
|
keyAlias relKeyAlias
|
||||||
// storeFile file(relStoreFile)
|
storeFile file('./keystore')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,22 +65,25 @@ android {
|
|||||||
flavorDimensions "Default"
|
flavorDimensions "Default"
|
||||||
productFlavors {
|
productFlavors {
|
||||||
driver {
|
driver {
|
||||||
versionCode 6
|
applicationId "h_mal.appttude.com.driver"
|
||||||
versionName "1.0.5"
|
versionCode 7
|
||||||
|
versionName "2.0.0"
|
||||||
}
|
}
|
||||||
admin {
|
admin {
|
||||||
applicationIdSuffix ".admin"
|
applicationId "h_mal.appttude.com.driver.admin"
|
||||||
versionCode 4
|
versionCode 4
|
||||||
versionName "0.0.5"
|
versionName "0.0.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sourceSets {
|
sourceSets {
|
||||||
driver {
|
driver {
|
||||||
|
java.srcDirs += 'src/driver/java'
|
||||||
manifest {
|
manifest {
|
||||||
srcFile 'src/driver/AndroidManifest.xml'
|
srcFile 'src/driver/AndroidManifest.xml'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
admin {
|
admin {
|
||||||
|
java.srcDirs += 'src/admin/java'
|
||||||
manifest {
|
manifest {
|
||||||
srcFile 'src/admin/AndroidManifest.xml'
|
srcFile 'src/admin/AndroidManifest.xml'
|
||||||
}
|
}
|
||||||
@@ -108,6 +110,7 @@ dependencies {
|
|||||||
implementation 'androidx.viewpager:viewpager:1.0.0'
|
implementation 'androidx.viewpager:viewpager:1.0.0'
|
||||||
implementation "androidx.legacy:legacy-support-v4:1.0.0"
|
implementation "androidx.legacy:legacy-support-v4:1.0.0"
|
||||||
testImplementation "junit:junit:4.13.2"
|
testImplementation "junit:junit:4.13.2"
|
||||||
|
implementation "androidx.preference:preference-ktx:1.2.0"
|
||||||
/ * Android Espresso */
|
/ * Android Espresso */
|
||||||
def testJunitVersion = "1.1.5"
|
def testJunitVersion = "1.1.5"
|
||||||
def testRunnerVersion = "1.5.2"
|
def testRunnerVersion = "1.5.2"
|
||||||
@@ -117,6 +120,8 @@ dependencies {
|
|||||||
androidTestImplementation "androidx.test.espresso.idling:idling-concurrent:$espressoVersion"
|
androidTestImplementation "androidx.test.espresso.idling:idling-concurrent:$espressoVersion"
|
||||||
implementation "androidx.test.espresso:espresso-idling-resource:$espressoVersion"
|
implementation "androidx.test.espresso:espresso-idling-resource:$espressoVersion"
|
||||||
androidTestImplementation "androidx.test:runner:$testRunnerVersion"
|
androidTestImplementation "androidx.test:runner:$testRunnerVersion"
|
||||||
|
androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion"
|
||||||
|
androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion"
|
||||||
/ * Google play services */
|
/ * Google play services */
|
||||||
implementation "com.google.android.gms:play-services-auth:20.4.1"
|
implementation "com.google.android.gms:play-services-auth:20.4.1"
|
||||||
/ * Google firebase */
|
/ * Google firebase */
|
||||||
@@ -128,6 +133,7 @@ dependencies {
|
|||||||
implementation "com.google.firebase:firebase-auth:$firebaseAuth"
|
implementation "com.google.firebase:firebase-auth:$firebaseAuth"
|
||||||
implementation "com.google.firebase:firebase-storage:$firebaseStorage"
|
implementation "com.google.firebase:firebase-storage:$firebaseStorage"
|
||||||
implementation "com.google.firebase:firebase-database:$firebaseDatabase"
|
implementation "com.google.firebase:firebase-database:$firebaseDatabase"
|
||||||
|
implementation 'com.firebaseui:firebase-ui-database:8.0.2'
|
||||||
/ * Photoviewer */
|
/ * Photoviewer */
|
||||||
implementation "com.github.chrisbanes:PhotoView:2.1.0"
|
implementation "com.github.chrisbanes:PhotoView:2.1.0"
|
||||||
/ * Picasso photo loader */
|
/ * Picasso photo loader */
|
||||||
@@ -151,4 +157,10 @@ dependencies {
|
|||||||
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
|
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
|
||||||
/ * Kotlin Reflect */
|
/ * Kotlin Reflect */
|
||||||
implementation "org.jetbrains.kotlin:kotlin-reflect:1.8.10"
|
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'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<!-- To auto-complete the email text field in the login form with the user's emails -->
|
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
|
||||||
|
|
||||||
<application
|
|
||||||
android:icon="@mipmap/ic_launcher"
|
|
||||||
android:roundIcon="@mipmap/ic_launcher_round">
|
|
||||||
|
|
||||||
</application>
|
|
||||||
|
|
||||||
</manifest>
|
|
||||||
@@ -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 <T : ViewModel> create(modelClass: Class<T>): 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<T : Any> : 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<T>(0)
|
||||||
|
io {
|
||||||
|
doTryOperation("Failed to retrieve ${clazz.simpleName}") {
|
||||||
|
val data = getDatabaseRef(uid).getDataFromDatabaseRef(clazz.java)
|
||||||
|
onSuccess(data ?: FirebaseCompletion.Default)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<V : DataViewerBaseViewModel<T>, VB : ViewBinding, T : Any> :
|
||||||
|
BaseFragment<V, VB>() {
|
||||||
|
|
||||||
|
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<T>(2)) }?.isTrue {
|
||||||
|
setFields(data as T)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun setFields(data: T) {}
|
||||||
|
|
||||||
|
fun viewsToHide(vararg view: View) {
|
||||||
|
view.forEach { it.hide() }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,34 +1,13 @@
|
|||||||
package h_mal.appttude.com.driver.admin.objects
|
package h_mal.appttude.com.driver.objects
|
||||||
|
|
||||||
|
|
||||||
class ApprovalsObject {
|
data class ApprovalsObject (
|
||||||
var driver_details_approval: Int = 0
|
var driver_details_approval: Int = 0,
|
||||||
var driver_license_approval: Int = 0
|
var driver_license_approval: Int = 0,
|
||||||
var private_hire_approval: Int = 0
|
var private_hire_approval: Int = 0,
|
||||||
var vehicle_details_approval: Int = 0
|
var vehicle_details_approval: Int = 0,
|
||||||
var mot_details_approval: Int = 0
|
var mot_details_approval: Int = 0,
|
||||||
var insurance_details_approval: Int = 0
|
var insurance_details_approval: Int = 0,
|
||||||
var log_book_approval: Int = 0
|
var log_book_approval: Int = 0,
|
||||||
var ph_car_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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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 h_mal.appttude.com.driver.model.DriversLicense
|
||||||
import java.util.*
|
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<String, DriversLicense>? = null
|
|
||||||
var private_hire: HashMap<String, PrivateHireLicense>? = null
|
|
||||||
var vehicle_details: HashMap<String, VehicleProfile>? = null
|
|
||||||
var insurance_details: HashMap<String, Insurance>? = null
|
|
||||||
var mot_details: HashMap<String, Mot>? = null
|
|
||||||
var log_book: HashMap<String, Logbook>? = null
|
|
||||||
var ph_car: HashMap<String, PrivateHireVehicle>? = null
|
|
||||||
|
|
||||||
constructor()
|
data class ArchiveObject(
|
||||||
constructor(
|
var driver_license: HashMap<String, DriversLicense>? = HashMap(),
|
||||||
driver_license: HashMap<String, DriversLicense>?,
|
var private_hire: HashMap<String, PrivateHireLicense>? = HashMap(),
|
||||||
private_hire: HashMap<String, PrivateHireLicense>?,
|
var vehicle_details: HashMap<String, VehicleProfile>? = HashMap(),
|
||||||
vehicle_details: HashMap<String, VehicleProfile>?,
|
var insurance_details: HashMap<String, Insurance>? = HashMap(),
|
||||||
insurance_details: HashMap<String, Insurance>?,
|
var mot_details: HashMap<String, Mot>? = HashMap(),
|
||||||
mot_details: HashMap<String, Mot>?,
|
var log_book: HashMap<String, Logbook>? = HashMap(),
|
||||||
log_book: HashMap<String, Logbook>?,
|
var ph_car: HashMap<String, PrivateHireVehicle>? = HashMap(),
|
||||||
private_hire_vehicle: HashMap<String, PrivateHireVehicle>?
|
)
|
||||||
) {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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 {
|
@IgnoreExtraProperties
|
||||||
var profileName: String? = null
|
data class UserObject (
|
||||||
var profileEmail: String? = null
|
var profileName: String? = "",
|
||||||
var profilePicString: String? = null
|
var profileEmail: String? = "",
|
||||||
|
var profilePicString: String? = "",
|
||||||
constructor()
|
)
|
||||||
constructor(profileName: String?, profileEmail: String?, profilePicString: String?) {
|
|
||||||
this.profileName = profileName
|
|
||||||
this.profileEmail = profileEmail
|
|
||||||
this.profilePicString = profilePicString
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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.objects.wholeObject.DriverProfile
|
||||||
import h_mal.appttude.com.driver.admin.objects.wholeObject.VehicleProfile
|
import h_mal.appttude.com.driver.objects.wholeObject.VehicleProfile
|
||||||
|
|
||||||
|
|
||||||
class WholeDriverObject {
|
data class WholeDriverObject(
|
||||||
var driver_profile: DriverProfile? = null
|
var driver_profile: DriverProfile? = DriverProfile(),
|
||||||
var role: String? = null
|
var role: String? = "",
|
||||||
var archive: ArchiveObject? = null
|
var archive: ArchiveObject? = ArchiveObject(),
|
||||||
var user_details: UserObject? = null
|
var user_details: UserObject? = UserObject(),
|
||||||
var vehicle_profile: VehicleProfile? = null
|
var vehicle_profile: VehicleProfile? = VehicleProfile(),
|
||||||
var approvalsObject: ApprovalsObject? = null
|
var approvalsObject: ApprovalsObject? = ApprovalsObject(),
|
||||||
var driver_number: String? = null
|
var driver_number: String? = "",
|
||||||
|
)
|
||||||
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()
|
|
||||||
}
|
|
||||||
@@ -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.DriverProfile
|
||||||
import h_mal.appttude.com.driver.model.DriversLicense
|
import h_mal.appttude.com.driver.model.DriversLicense
|
||||||
import h_mal.appttude.com.driver.model.PrivateHireLicense
|
import h_mal.appttude.com.driver.model.PrivateHireLicense
|
||||||
|
|
||||||
|
|
||||||
class DriverProfile {
|
data class DriverProfile(
|
||||||
var driver_profile: DriverProfile? = null
|
var driver_profile: DriverProfile? = DriverProfile(),
|
||||||
var driver_license: DriversLicense? = null
|
var driver_license: DriversLicense? = DriversLicense(),
|
||||||
var private_hire: PrivateHireLicense? = null
|
var private_hire: PrivateHireLicense? = PrivateHireLicense(),
|
||||||
|
)
|
||||||
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()
|
|
||||||
}
|
|
||||||
@@ -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<MappedObject?> =
|
|
||||||
object : Parcelable.Creator<MappedObject?> {
|
|
||||||
override fun createFromParcel(`in`: Parcel): MappedObject? {
|
|
||||||
return MappedObject(`in`)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun newArray(size: Int): Array<MappedObject?> {
|
|
||||||
return arrayOfNulls(size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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.Insurance
|
||||||
import h_mal.appttude.com.driver.model.Logbook
|
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.Mot
|
||||||
|
import h_mal.appttude.com.driver.model.PrivateHireVehicle
|
||||||
import h_mal.appttude.com.driver.model.VehicleProfile
|
import h_mal.appttude.com.driver.model.VehicleProfile
|
||||||
|
|
||||||
|
data class VehicleProfile (
|
||||||
class VehicleProfile {
|
var insurance_details: Insurance? = Insurance(),
|
||||||
var insurance_details: Insurance? = null
|
var log_book: Logbook? = Logbook(),
|
||||||
var log_book: Logbook? = null
|
var mot_details: Mot? = Mot(),
|
||||||
var mot_details: Mot? = null
|
var vehicle_details: VehicleProfile? = VehicleProfile(),
|
||||||
var vehicle_details: VehicleProfile? = null
|
var privateHireVehicle: PrivateHireVehicle? = PrivateHireVehicle()
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,188 +1,57 @@
|
|||||||
package h_mal.appttude.com.driver.ui
|
package h_mal.appttude.com.driver.ui
|
||||||
|
|
||||||
import android.app.Activity
|
import android.content.Context
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.ArrayAdapter
|
import android.widget.ArrayAdapter
|
||||||
import h_mal.appttude.com.driver.admin.objects.wholeObject.MappedObject
|
import h_mal.appttude.com.driver.databinding.ApprovalListItemBinding
|
||||||
import h_mal.appttude.com.driver.R
|
import h_mal.appttude.com.driver.model.ApprovalStatus
|
||||||
|
import h_mal.appttude.com.driver.utils.hide
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
|
||||||
class ApprovalListAdapter(
|
class ApprovalListAdapter(
|
||||||
private val activity: Activity,
|
private val context: Context,
|
||||||
objects: Array<MappedObject?>
|
private val data: List<Pair<String, ApprovalStatus>>,
|
||||||
) : ArrayAdapter<MappedObject?>(activity, 0, objects) {
|
private val callback: (String) -> Unit
|
||||||
|
) : ArrayAdapter<Pair<String, ApprovalStatus>>(context, 0, data) {
|
||||||
|
|
||||||
var mappedObject: MappedObject? = objects[0]
|
override fun getCount(): Int = data.size
|
||||||
|
|
||||||
var names: Array<String> = 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 {
|
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||||
var listItemView: View? = convertView
|
var listItemView: View? = convertView
|
||||||
|
val binding: ApprovalListItemBinding
|
||||||
if (listItemView == null) {
|
if (listItemView == null) {
|
||||||
listItemView = LayoutInflater.from(activity).inflate(
|
// Inflate view binding into listview cell
|
||||||
R.layout.approval_list_grid_item, parent, false
|
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)
|
val key: String = getItem(position)?.first ?: throw IOException("No document name provided")
|
||||||
// textView.text = names.get(position)
|
val approvalStatus: ApprovalStatus? = getItem(position)?.second
|
||||||
// val imageView: ImageView = listItemView.findViewById(R.id.approval_iv)
|
|
||||||
// imageView.setImageResource(
|
binding.approvalText.text = key
|
||||||
// MainActivity.approvalsClass!!.setImageResource(
|
approvalStatus?.let { item ->
|
||||||
// approvalCode
|
item.score.takeIf { it != 0 }?.let {
|
||||||
// )
|
binding.root.setOnClickListener { callback.invoke(key) }
|
||||||
// )
|
}
|
||||||
// imageView.setOnClickListener {
|
binding.approvalIv.setImageResource(item.drawableId)
|
||||||
// SetApprovalDialog(
|
binding.approvalStatus.text = context.getString(item.stringId)
|
||||||
// approvalCode,
|
}
|
||||||
// activity,
|
// hide divider for first cell
|
||||||
// mappedObject.userId,
|
if (position == 0) binding.divider.hide()
|
||||||
// position,
|
|
||||||
// imageView
|
return (listItemView)
|
||||||
// )
|
|
||||||
// }
|
|
||||||
// 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)!!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// override fun getCount(): Int {
|
fun updateAdapter(date: List<Pair<String, ApprovalStatus>>) {
|
||||||
// return 8
|
clear()
|
||||||
// }
|
addAll(date)
|
||||||
//
|
}
|
||||||
// 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)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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<ApproverViewModel, FragmentApproverBinding>() {
|
||||||
|
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<DriverOverviewViewModel, FragmentUserMainBinding>() {
|
||||||
|
|
||||||
|
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<Pair<String, ApprovalStatus>>
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<String> = 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<Void>() {
|
|
||||||
// @Override
|
|
||||||
// public void onComplete(@NonNull Task<Void> 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;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
@@ -1,153 +1,208 @@
|
|||||||
package h_mal.appttude.com.driver.ui
|
package h_mal.appttude.com.driver.ui
|
||||||
|
|
||||||
import android.app.AlertDialog
|
import android.app.AlertDialog
|
||||||
import android.content.DialogInterface
|
|
||||||
import android.content.SharedPreferences
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import androidx.fragment.app.Fragment
|
import android.widget.EditText
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import android.widget.LinearLayout
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
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.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 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.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
class HomeSuperUserFragment : Fragment() {
|
class HomeSuperUserFragment : BaseFragment<SuperUserViewModel, FragmentHomeSuperUserBinding>(),
|
||||||
var users: DatabaseReference? = null
|
MenuProvider {
|
||||||
var mappedObjectList: MutableList<MappedObject>? = null
|
private lateinit var adapter: FirebaseRecyclerAdapter<WholeDriverObject, CustomViewHolder<ListItemLayoutBinding>>
|
||||||
private var sharedPreferences: SharedPreferences? = null
|
|
||||||
private var sortOrder: Int = 0
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
private val sortDesc: Boolean = false
|
super.onViewCreated(view, savedInstanceState)
|
||||||
private var recyclerViewAdapter: RecyclerViewAdapter? = null
|
requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED)
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
viewModel.retrieveDefaultFirebaseOptions()
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
setHasOptionsMenu(true)
|
|
||||||
mappedObjectList = ArrayList()
|
|
||||||
users!!.addValueEventListener(valueEventListener)
|
|
||||||
sharedPreferences = requireActivity().getSharedPreferences("PREFS", 0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onSuccess(data: Any?) {
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
super.onSuccess(data)
|
||||||
savedInstanceState: Bundle?
|
when (data) {
|
||||||
): View? {
|
is FirebaseRecyclerOptions<*> -> setAdapterToRecyclerView(data)
|
||||||
// Inflate the layout for this fragment
|
}
|
||||||
val view: View = inflater.inflate(R.layout.fragment_home_super_user, container, false)
|
}
|
||||||
|
private fun setNonView(status: DatabaseStatus) {
|
||||||
view.findViewById<RecyclerView>(R.id.recycler_view).apply {
|
applyBinding {
|
||||||
layoutManager = LinearLayoutManager(context)
|
emptyView.run {
|
||||||
recyclerViewAdapter = RecyclerViewAdapter(context, mappedObjectList)
|
root.setOnClickListener(null)
|
||||||
adapter = recyclerViewAdapter
|
root.visibility = View.VISIBLE
|
||||||
|
icon.setImageResource(status.drawable)
|
||||||
|
header.setText(status.header)
|
||||||
|
subtext.setText(status.subtext)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return view
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var valueEventListener: ValueEventListener = object : ValueEventListener {
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun onDataChange(snapshot: DataSnapshot) {
|
private fun setAdapterToRecyclerView(options: FirebaseRecyclerOptions<*>) {
|
||||||
mappedObjectList!!.clear()
|
applyBinding {
|
||||||
Log.i("Count ", "" + snapshot.childrenCount)
|
progressCircular.show()
|
||||||
for (postSnapshot: DataSnapshot in snapshot.children) {
|
if (recyclerView.adapter == null) {
|
||||||
if ((postSnapshot.child("role").value.toString() == "driver")) {
|
// create an adapter for the first time
|
||||||
mappedObjectList!!.add(
|
adapter = createAdapter(options = options as FirebaseRecyclerOptions<WholeDriverObject>)
|
||||||
MappedObject(
|
recyclerView.adapter = adapter
|
||||||
postSnapshot.key, postSnapshot.getValue(
|
recyclerView.setHasFixedSize(true)
|
||||||
WholeDriverObject::class.java
|
adapter.startListening()
|
||||||
)
|
} else {
|
||||||
|
adapter.updateOptions(options as FirebaseRecyclerOptions<WholeDriverObject>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
applyBinding {
|
||||||
|
if (recyclerView.adapter != null) {
|
||||||
|
adapter.startListening()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
super.onStop()
|
||||||
|
adapter.stopListening()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createAdapter(options: FirebaseRecyclerOptions<WholeDriverObject>): BaseFirebaseAdapter<WholeDriverObject, ListItemLayoutBinding> {
|
||||||
|
return object :
|
||||||
|
BaseFirebaseAdapter<WholeDriverObject, ListItemLayoutBinding>(options, layoutInflater) {
|
||||||
|
override fun onBindViewHolder(
|
||||||
|
holder: CustomViewHolder<ListItemLayoutBinding>,
|
||||||
|
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 onDataChanged() {
|
||||||
|
super.onDataChanged()
|
||||||
override fun onCancelled(databaseError: DatabaseError) {
|
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 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<String> = 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<MappedObject> = object : Comparator<MappedObject> {
|
|
||||||
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 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 fun showChangeNumberDialog(defaultNumber: String, uid: String) {
|
||||||
private val SORT: String = "SORT"
|
val inputText = EditText(context).apply {
|
||||||
private val REVERSED: String = "REVERSED"
|
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<String> = 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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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<MappedObject>?) :
|
|
||||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<MappedObject>("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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<DriverLicenseViewModel, FragmentDriverLicenseBinding, DriversLicense>() {
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<DriverProfileViewModel, FragmentDriverProfileBinding, DriverProfile>() {
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<PrivateHireLicenseViewModel, FragmentPrivateHireLicenseBinding, PrivateHireLicense>() {
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<InsuranceViewModel, FragmentInsuranceBinding, Insurance>() {
|
||||||
|
|
||||||
|
override fun setupView(binding: FragmentInsuranceBinding) {
|
||||||
|
super.setupView(binding)
|
||||||
|
viewsToHide(binding.submit, binding.uploadInsurance)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun updateImageCarousal(list: List<Any?>) {
|
||||||
|
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) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<LogbookViewModel, FragmentLogbookBinding, Logbook>() {
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<MotViewModel, FragmentMotBinding, Mot>() {
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<PrivateHireVehicleViewModel, FragmentPrivateHireLicenseBinding, PrivateHireVehicle>() {
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<VehicleProfileViewModel, FragmentVehicleSetupBinding, VehicleProfile>() {
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package h_mal.appttude.com.driver.utils
|
||||||
|
|
||||||
|
const val FRAGMENT = "fragment"
|
||||||
@@ -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<Int>()
|
||||||
|
score = data?.let { ApprovalStatus.getByScore(it) } ?: ApprovalStatus.NOT_SUBMITTED
|
||||||
|
onSuccess(FirebaseCompletion.Default)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFragmentClass(): Class<out Fragment> {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<DriversLicense>() {
|
||||||
|
|
||||||
|
override fun getDatabaseRef(uid: String) = database.getDriverLicenseRef(uid)
|
||||||
|
}
|
||||||
@@ -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<ApprovalsObject>(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<ApprovalsObject>()
|
||||||
|
|
||||||
|
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<Pair<String, ApprovalStatus>> {
|
||||||
|
val list = mutableListOf<Pair<String, ApprovalStatus>>()
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<DriverProfile>() {
|
||||||
|
override fun getDatabaseRef(uid: String) = database.getDriverDetailsRef(uid)
|
||||||
|
}
|
||||||
@@ -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<Insurance>() {
|
||||||
|
|
||||||
|
override fun getDatabaseRef(uid: String) = database.getInsuranceDetailsRef(uid)
|
||||||
|
}
|
||||||
@@ -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<Logbook>() {
|
||||||
|
|
||||||
|
override fun getDatabaseRef(uid: String) = database.getLogbookRef(uid)
|
||||||
|
}
|
||||||
@@ -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<Mot>() {
|
||||||
|
|
||||||
|
override fun getDatabaseRef(uid: String) = database.getMotDetailsRef(uid)
|
||||||
|
}
|
||||||
@@ -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<PrivateHireLicense>() {
|
||||||
|
|
||||||
|
override fun getDatabaseRef(uid: String) = database.getPrivateHireRef(uid)
|
||||||
|
}
|
||||||
@@ -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<PrivateHireVehicle>() {
|
||||||
|
|
||||||
|
override fun getDatabaseRef(uid: String) = database.getPrivateHireVehicleRef(uid)
|
||||||
|
}
|
||||||
@@ -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<WholeDriverObject>()
|
||||||
|
.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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<VehicleProfile>() {
|
||||||
|
|
||||||
|
override fun getDatabaseRef(uid: String) = database.getVehicleDetailsRef(uid)
|
||||||
|
}
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<androidx.cardview.widget.CardView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
app:cardCornerRadius="22dp"
|
|
||||||
app:cardBackgroundColor="@android:color/transparent"
|
|
||||||
app:cardElevation="0dp">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:src="@drawable/cardviewoutline" />
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_centerInParent="true"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/approval_iv"
|
|
||||||
android:layout_width="64dp"
|
|
||||||
android:layout_height="64dp"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
tools:src="@drawable/pending" />
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:id="@+id/view_1"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="3dp"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:layout_centerVertical="true" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/approval_text"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:textSize="17sp"
|
|
||||||
android:textStyle="bold"
|
|
||||||
tools:text="Private Hire License" />
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:layout_width="24dp"
|
|
||||||
android:layout_height="24dp"
|
|
||||||
android:layout_alignParentTop="true"
|
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_margin="12dp">
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_gravity="center" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/archive_icon"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:src="@drawable/ic_archive_black_24dp"
|
|
||||||
app:tint="@color/colour_three" />
|
|
||||||
</FrameLayout>
|
|
||||||
</RelativeLayout>
|
|
||||||
</androidx.cardview.widget.CardView>
|
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
63
app/src/admin/res/layout/approval_list_item.xml
Normal file
63
app/src/admin/res/layout/approval_list_item.xml
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/divider"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@color/colour_ten"
|
||||||
|
android:paddingEnd="28dp"
|
||||||
|
app:layout_constraintLeft_toLeftOf="@id/approval_status"
|
||||||
|
app:layout_constraintRight_toRightOf="@id/approval_status"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:ignore="RtlSymmetry" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/approval_iv"
|
||||||
|
android:layout_width="@dimen/status_size"
|
||||||
|
android:layout_height="@dimen/status_size"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginStart="28dp"
|
||||||
|
android:layout_marginTop="9dp"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:src="@drawable/pending"
|
||||||
|
android:contentDescription="@string/approval_status" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/approval_status"
|
||||||
|
style="@style/subheader"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginLeft="28dp"
|
||||||
|
android:layout_marginRight="28dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/approval_iv"
|
||||||
|
app:layout_constraintLeft_toRightOf="@id/approval_iv"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/approval_iv"
|
||||||
|
tools:text="Pending Approval" />
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/approval_text"
|
||||||
|
style="@style/headerStyle"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginTop="0dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:paddingBottom="9dp"
|
||||||
|
app:layout_constraintLeft_toLeftOf="@id/approval_status"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/approval_status"
|
||||||
|
tools:text="Private Hire License" />
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
16
app/src/admin/res/layout/empty_layout.xml
Normal file
16
app/src/admin/res/layout/empty_layout.xml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/empty_view_message"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"/>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
53
app/src/admin/res/layout/empty_users_view.xml
Normal file
53
app/src/admin/res/layout/empty_users_view.xml
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:src="@drawable/splash_screen"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
android:paddingTop="@dimen/default_indicator_margin_horizontal"
|
||||||
|
android:layout_marginTop="@dimen/default_indicator_margin_horizontal"
|
||||||
|
app:layout_constraintHeight_percent="0.5"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
android:importantForAccessibility="no" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
style="@style/constraint_container">
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/icon"
|
||||||
|
android:layout_width="80dp"
|
||||||
|
android:layout_height="80dp"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/header"
|
||||||
|
android:src="@drawable/baseline_inbox_24"
|
||||||
|
android:contentDescription="@string/image_icon_for_feedback_view" />
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/header"
|
||||||
|
style="@style/headerStyle"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/no_drivers_to_show"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/subtext"
|
||||||
|
style="@style/subheader"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/header"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/no_drivers_subtext"/>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
53
app/src/admin/res/layout/fragment_approver.xml
Normal file
53
app/src/admin/res/layout/fragment_approver.xml
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
tools:context=".ui.ApproverFragment">
|
||||||
|
|
||||||
|
<androidx.fragment.app.FragmentContainerView
|
||||||
|
android:id="@+id/container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/buttonContainer"
|
||||||
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_bias="0.0"
|
||||||
|
tools:layout="@layout/fragment_private_hire_license" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/buttonContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
tools:ignore="RtlHardcoded">
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/approve"
|
||||||
|
android:layout_marginLeft="12dp"
|
||||||
|
android:layout_marginRight="6dp"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
style="@style/TextButton.WithIcon"
|
||||||
|
app:icon="@drawable/baseline_check_24"
|
||||||
|
android:text="@string/approve" />
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/decline"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_marginLeft="6dp"
|
||||||
|
android:layout_marginRight="12dp"
|
||||||
|
style="@style/TextButton.WithIcon"
|
||||||
|
app:icon="@drawable/baseline_clear_24"
|
||||||
|
app:iconTint="@android:color/holo_red_light"
|
||||||
|
android:backgroundTint="@color/colour_ten"
|
||||||
|
android:text="@string/decline" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -1,16 +1,42 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:id="@+id/container"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
tools:context=".ui.HomeSuperUserFragment">
|
tools:context=".ui.HomeSuperUserFragment">
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/recycler_view"
|
android:id="@+id/recycler_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
android:orientation="vertical"
|
||||||
tools:listitem="@layout/list_item_layout">
|
tools:listitem="@layout/list_item_layout">
|
||||||
|
|
||||||
</androidx.recyclerview.widget.RecyclerView>
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
|
||||||
</RelativeLayout>
|
<ProgressBar
|
||||||
|
android:id="@+id/progress_circular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible"/>
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/empty_view"
|
||||||
|
layout="@layout/empty_users_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible"/>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -1,17 +1,32 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
style="@style/parent_constraint_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".ui.UserMainFragment">
|
tools:context=".ui.DriverOverviewFragment">
|
||||||
|
|
||||||
<GridView
|
<androidx.cardview.widget.CardView
|
||||||
android:id="@+id/approvals_list"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:numColumns="2"
|
android:layout_gravity="center"
|
||||||
android:rowCount="4"
|
android:layout_marginBottom="12dp"
|
||||||
android:stretchMode="columnWidth"
|
app:cardBackgroundColor="@color/colour_nine"
|
||||||
tools:listitem="@layout/approval_list_grid_item" />
|
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">
|
||||||
|
|
||||||
</RelativeLayout>
|
<ListView
|
||||||
|
android:id="@+id/approvals_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:divider="@color/colour_three"
|
||||||
|
tools:layout_height="658dp"
|
||||||
|
tools:listitem="@layout/approval_list_item" />
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
android:id="@+id/driverPic"
|
android:id="@+id/driverPic"
|
||||||
android:layout_width="50dp"
|
android:layout_width="50dp"
|
||||||
android:layout_height="50dp"
|
android:layout_height="50dp"
|
||||||
android:layout_marginLeft="24dp"
|
android:layout_marginStart="24dp"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:layout_marginBottom="24dp"
|
android:layout_marginBottom="24dp"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
@@ -26,18 +26,19 @@
|
|||||||
android:id="@+id/approval_iv"
|
android:id="@+id/approval_iv"
|
||||||
android:layout_width="10dp"
|
android:layout_width="10dp"
|
||||||
android:layout_height="10dp"
|
android:layout_height="10dp"
|
||||||
android:layout_marginRight="3dp"
|
android:layout_marginEnd="3dp"
|
||||||
android:layout_marginTop="3dp"
|
android:layout_marginTop="3dp"
|
||||||
app:layout_constraintTop_toTopOf="@id/driverPic"
|
app:layout_constraintTop_toTopOf="@id/driverPic"
|
||||||
app:layout_constraintRight_toRightOf="@id/driverPic"
|
app:layout_constraintRight_toRightOf="@id/driverPic"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
tools:src="@android:drawable/presence_online" />
|
tools:src="@android:drawable/presence_online"
|
||||||
|
android:contentDescription="@string/user_status" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/driver_no"
|
android:id="@+id/driver_no"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginRight="24dp"
|
android:layout_marginEnd="24dp"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
@@ -48,7 +49,7 @@
|
|||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_marginLeft="24dp"
|
android:layout_marginStart="24dp"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/driverPic"
|
app:layout_constraintBottom_toBottomOf="@id/driverPic"
|
||||||
app:layout_constraintLeft_toRightOf="@id/driverPic"
|
app:layout_constraintLeft_toRightOf="@id/driverPic"
|
||||||
|
|||||||
@@ -5,11 +5,34 @@
|
|||||||
android:id="@+id/main_navigation"
|
android:id="@+id/main_navigation"
|
||||||
app:startDestination="@id/homeAdminFragment">
|
app:startDestination="@id/homeAdminFragment">
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:id="@+id/nav_user_settings"
|
||||||
|
android:name="h_mal.appttude.com.driver.ui.update.UpdateActivity"
|
||||||
|
android:label="fragment_profile"
|
||||||
|
tools:layout="@layout/update_activity" />
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/homeAdminFragment"
|
android:id="@+id/homeAdminFragment"
|
||||||
android:name="h_mal.appttude.com.driver.ui.HomeSuperUserFragment"
|
android:name="h_mal.appttude.com.driver.ui.HomeSuperUserFragment"
|
||||||
android:label="fragment_home"
|
android:label="fragment_home"
|
||||||
tools:layout="@layout/fragment_home_super_user">
|
tools:layout="@layout/fragment_home_super_user">
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_homeAdminFragment_to_userMainFragment"
|
||||||
|
app:destination="@id/userMainFragment" />
|
||||||
</fragment>
|
</fragment>
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/userMainFragment"
|
||||||
|
android:name="h_mal.appttude.com.driver.ui.DriverOverviewFragment"
|
||||||
|
android:label="fragment_user_main"
|
||||||
|
tools:layout="@layout/fragment_user_main">
|
||||||
|
|
||||||
|
<action
|
||||||
|
android:id="@+id/to_approverFragment"
|
||||||
|
app:destination="@id/approverFragment" />
|
||||||
|
</fragment>
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/approverFragment"
|
||||||
|
android:name="h_mal.appttude.com.driver.ui.ApproverFragment"
|
||||||
|
android:label="fragment_approver"
|
||||||
|
tools:layout="@layout/fragment_approver" />
|
||||||
|
|
||||||
</navigation>
|
</navigation>
|
||||||
5
app/src/admin/res/values/strings.xml
Normal file
5
app/src/admin/res/values/strings.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<resources>
|
||||||
|
<string name="app_name">Driver Admin</string>
|
||||||
|
<!-- TODO: Remove or change this placeholder text -->
|
||||||
|
<string name="hello_blank_fragment">Hello blank fragment</string>
|
||||||
|
</resources>
|
||||||
@@ -1,17 +1,44 @@
|
|||||||
package h_mal.appttude.com.driver
|
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.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.annotation.StringRes
|
||||||
|
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||||
import androidx.test.espresso.Espresso.onData
|
import androidx.test.espresso.Espresso.onData
|
||||||
import androidx.test.espresso.Espresso.onView
|
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.ViewInteraction
|
||||||
import androidx.test.espresso.action.ViewActions
|
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.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.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.allOf
|
||||||
import org.hamcrest.CoreMatchers.anything
|
import org.hamcrest.CoreMatchers.anything
|
||||||
|
import org.hamcrest.Matcher
|
||||||
|
import org.hamcrest.Matchers
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
open class BaseTestRobot {
|
open class BaseTestRobot {
|
||||||
|
|
||||||
fun fillEditText(resId: Int, text: String?): ViewInteraction =
|
fun fillEditText(resId: Int, text: String?): ViewInteraction =
|
||||||
@@ -21,25 +48,133 @@ open class BaseTestRobot {
|
|||||||
)
|
)
|
||||||
|
|
||||||
fun clickButton(resId: Int): ViewInteraction =
|
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
|
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) {
|
fun clickListItem(listRes: Int, position: Int) {
|
||||||
onData(anything())
|
onData(anything())
|
||||||
.inAdapterView(allOf(withId(listRes)))
|
.inAdapterView(allOf(withId(listRes)))
|
||||||
.atPosition(position).perform(ViewActions.click())
|
.atPosition(position).perform(click())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <VH : ViewHolder> scrollToRecyclerItem(recyclerId: Int, text: String): ViewInteraction? {
|
||||||
|
return matchView(recyclerId)
|
||||||
|
.perform(
|
||||||
|
// scrollTo will fail the test if no item matches.
|
||||||
|
RecyclerViewActions.scrollTo<VH>(
|
||||||
|
hasDescendant(withText(text))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <VH : ViewHolder> scrollToRecyclerItem(recyclerId: Int, resIdForString: Int): ViewInteraction? {
|
||||||
|
return matchView(recyclerId)
|
||||||
|
.perform(
|
||||||
|
// scrollTo will fail the test if no item matches.
|
||||||
|
RecyclerViewActions.scrollTo<VH>(
|
||||||
|
hasDescendant(withText(resIdForString))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <VH : ViewHolder> scrollToRecyclerItemByPosition(recyclerId: Int, position: Int): ViewInteraction? {
|
||||||
|
return matchView(recyclerId)
|
||||||
|
.perform(
|
||||||
|
// scrollTo will fail the test if no item matches.
|
||||||
|
RecyclerViewActions.scrollToPosition<VH>(position)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <VH : ViewHolder> clickViewInRecycler(recyclerId: Int, text: String) {
|
||||||
|
matchView(recyclerId)
|
||||||
|
.perform(
|
||||||
|
// scrollTo will fail the test if no item matches.
|
||||||
|
RecyclerViewActions.actionOnItem<VH>(hasDescendant(withText(text)), click())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <VH : ViewHolder> clickViewInRecycler(recyclerId: Int, resIdForString: Int) {
|
||||||
|
matchView(recyclerId)
|
||||||
|
.perform(
|
||||||
|
// scrollTo will fail the test if no item matches.
|
||||||
|
RecyclerViewActions.actionOnItem<VH>(hasDescendant(withText(resIdForString)), click())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <VH : ViewHolder> clickSubViewInRecycler(recyclerId: Int, text: String, subView: Int) {
|
||||||
|
scrollToRecyclerItem<VH>(recyclerId, text)
|
||||||
|
?.perform(
|
||||||
|
// scrollTo will fail the test if no item matches.
|
||||||
|
RecyclerViewActions.actionOnItem<VH>(
|
||||||
|
hasDescendant(withText(text)), object : ViewAction {
|
||||||
|
override fun getDescription(): String = "Matching recycler descendant"
|
||||||
|
override fun getConstraints(): Matcher<View>? = isRoot()
|
||||||
|
override fun perform(uiController: UiController?, view: View?) {
|
||||||
|
view?.findViewById<View>(subView)?.performClick()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkErrorOnTextEntry(resId: Int, errorMessage: String): ViewInteraction =
|
fun checkErrorOnTextEntry(resId: Int, errorMessage: String): ViewInteraction =
|
||||||
onView(withId(resId)).check(matches(checkErrorMessage(errorMessage)))
|
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 =
|
fun getStringFromResource(@StringRes resId: Int): String =
|
||||||
Resources.getSystem().getString(resId)
|
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<String>, 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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,35 +1,65 @@
|
|||||||
package h_mal.appttude.com.driver
|
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.View
|
||||||
|
import android.view.WindowManager
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.test.core.app.ActivityScenario
|
import androidx.test.core.app.ActivityScenario
|
||||||
|
import androidx.test.espresso.*
|
||||||
import androidx.test.espresso.Espresso.onView
|
import androidx.test.espresso.Espresso.onView
|
||||||
import androidx.test.espresso.IdlingRegistry
|
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||||
import androidx.test.espresso.IdlingResource
|
import androidx.test.espresso.matcher.ViewMatchers.*
|
||||||
import androidx.test.espresso.UiController
|
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
|
||||||
import androidx.test.espresso.ViewAction
|
import androidx.test.rule.GrantPermissionRule
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.isRoot
|
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
|
||||||
import h_mal.appttude.com.driver.base.BaseActivity
|
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.Matcher
|
||||||
|
import org.hamcrest.TypeSafeMatcher
|
||||||
|
import org.hamcrest.core.AllOf
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
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<T : BaseActivity<*,*>>(
|
open class BaseUiTest<T : BaseActivity<*, *>>(
|
||||||
private val activity: Class<T>
|
private val activity: Class<T>
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private lateinit var mActivityScenarioRule: ActivityScenario<T>
|
private lateinit var mActivityScenarioRule: ActivityScenario<T>
|
||||||
private var mIdlingResource: IdlingResource? = null
|
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
|
@Before
|
||||||
fun setup() {
|
fun setup() {
|
||||||
|
Screengrab.setDefaultScreenshotStrategy(UiAutomatorScreenshotStrategy())
|
||||||
beforeLaunch()
|
beforeLaunch()
|
||||||
mActivityScenarioRule = ActivityScenario.launch(activity)
|
mActivityScenarioRule = ActivityScenario.launch(activity)
|
||||||
mActivityScenarioRule.onActivity {
|
mActivityScenarioRule.onActivity {
|
||||||
mIdlingResource = it.getIdlingResource()!!
|
mIdlingResource = it.getIdlingResource()!!
|
||||||
IdlingRegistry.getInstance().register(mIdlingResource)
|
IdlingRegistry.getInstance().register(mIdlingResource)
|
||||||
|
afterLaunch(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,7 +71,7 @@ open class BaseUiTest<T : BaseActivity<*,*>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getResourceString(@StringRes stringRes: Int): String {
|
fun getResourceString(@StringRes stringRes: Int): String {
|
||||||
return InstrumentationRegistry.getInstrumentation().targetContext.resources.getString(
|
return getInstrumentation().targetContext.resources.getString(
|
||||||
stringRes
|
stringRes
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -49,7 +79,7 @@ open class BaseUiTest<T : BaseActivity<*,*>>(
|
|||||||
fun waitFor(delay: Long) {
|
fun waitFor(delay: Long) {
|
||||||
onView(isRoot()).perform(object : ViewAction {
|
onView(isRoot()).perform(object : ViewAction {
|
||||||
override fun getConstraints(): Matcher<View> = isRoot()
|
override fun getConstraints(): Matcher<View> = isRoot()
|
||||||
override fun getDescription(): String? = "wait for $delay milliseconds"
|
override fun getDescription(): String = "wait for $delay milliseconds"
|
||||||
override fun perform(uiController: UiController, v: View?) {
|
override fun perform(uiController: UiController, v: View?) {
|
||||||
uiController.loopMainThreadForAtLeast(delay)
|
uiController.loopMainThreadForAtLeast(delay)
|
||||||
}
|
}
|
||||||
@@ -57,4 +87,55 @@ open class BaseUiTest<T : BaseActivity<*,*>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
open fun beforeLaunch() {}
|
open fun beforeLaunch() {}
|
||||||
|
open fun afterLaunch(context: Context) {}
|
||||||
|
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
fun checkToastMessage(message: String) {
|
||||||
|
onView(withText(message)).inRoot(object : TypeSafeMatcher<Root>() {
|
||||||
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -7,4 +7,8 @@ const val deleteAccountFirebase =
|
|||||||
"http://10.0.2.2:9099/identitytoolkit.googleapis.com/v1/accounts:delete?key=$apiKey"
|
"http://10.0.2.2:9099/identitytoolkit.googleapis.com/v1/accounts:delete?key=$apiKey"
|
||||||
|
|
||||||
|
|
||||||
const val USER_PASSWORD = "LetMeIn123!"
|
const val USER_PASSWORD = "LetMeIn123!"
|
||||||
|
|
||||||
|
const val DRIVER_EMAIL = "existing-driver@driver.com"
|
||||||
|
const val ADMIN_EMAIL = "admin@driver.com"
|
||||||
|
const val PASSWORD = "test123456"
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
package h_mal.appttude.com.driver
|
package h_mal.appttude.com.driver
|
||||||
|
|
||||||
|
import android.graphics.drawable.BitmapDrawable
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
|
import android.widget.ImageView
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
import org.hamcrest.Description
|
import org.hamcrest.Description
|
||||||
import org.hamcrest.Matcher
|
import org.hamcrest.Matcher
|
||||||
@@ -11,7 +13,7 @@ import org.hamcrest.TypeSafeMatcher
|
|||||||
/**
|
/**
|
||||||
* Matcher for testing error of TextInputLayout
|
* Matcher for testing error of TextInputLayout
|
||||||
*/
|
*/
|
||||||
fun checkErrorMessage(expectedErrorText: String): Matcher<View?>? {
|
fun checkErrorMessage(expectedErrorText: String): Matcher<View?> {
|
||||||
return object : TypeSafeMatcher<View?>() {
|
return object : TypeSafeMatcher<View?>() {
|
||||||
override fun matchesSafely(view: View?): Boolean {
|
override fun matchesSafely(view: View?): Boolean {
|
||||||
if (view is EditText) {
|
if (view is EditText) {
|
||||||
@@ -28,3 +30,25 @@ fun checkErrorMessage(expectedErrorText: String): Matcher<View?>? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun checkImage(): Matcher<View?> {
|
||||||
|
return object : TypeSafeMatcher<View?>() {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,18 +5,23 @@ import com.google.firebase.database.FirebaseDatabase
|
|||||||
import com.google.firebase.storage.FirebaseStorage
|
import com.google.firebase.storage.FirebaseStorage
|
||||||
import h_mal.appttude.com.driver.base.BaseActivity
|
import h_mal.appttude.com.driver.base.BaseActivity
|
||||||
import h_mal.appttude.com.driver.data.FirebaseAuthSource
|
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.runBlocking
|
||||||
import kotlinx.coroutines.tasks.await
|
import kotlinx.coroutines.tasks.await
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.BeforeClass
|
import org.junit.BeforeClass
|
||||||
|
|
||||||
open class FirebaseTest<T : BaseActivity<*,*>>(
|
open class FirebaseTest<T : BaseActivity<*, *>>(
|
||||||
activity: Class<T>,
|
activity: Class<T>,
|
||||||
private val registered: Boolean = false,
|
private val registered: Boolean = false,
|
||||||
private val signedIn: Boolean = false
|
private val signedIn: Boolean = false,
|
||||||
|
private val signOutAfterTest: Boolean = true
|
||||||
) : BaseUiTest<T>(activity) {
|
) : BaseUiTest<T>(activity) {
|
||||||
|
|
||||||
private val firebaseAuthSource by lazy { FirebaseAuthSource() }
|
private val firebaseAuthSource by lazy { FirebaseAuthSource() }
|
||||||
|
private val firebaseDatabaseSource by lazy { FirebaseDatabaseSource() }
|
||||||
|
private val firebaseStorageSource by lazy { FirebaseStorageSource() }
|
||||||
|
|
||||||
private var email: String? = null
|
private var email: String? = null
|
||||||
|
|
||||||
@@ -45,9 +50,10 @@ open class FirebaseTest<T : BaseActivity<*,*>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
fun tearDownFirebase() = runBlocking {
|
fun tearDownFirebase() {
|
||||||
removeUser()
|
if (signOutAfterTest) {
|
||||||
firebaseAuthSource.logOut()
|
firebaseAuthSource.logOut()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun setupUser(
|
suspend fun setupUser(
|
||||||
@@ -58,6 +64,14 @@ open class FirebaseTest<T : BaseActivity<*,*>>(
|
|||||||
firebaseAuthSource.registerUser(signInEmail, password).await().user
|
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
|
// remove the user we created for testing
|
||||||
suspend fun removeUser() {
|
suspend fun removeUser() {
|
||||||
try {
|
try {
|
||||||
@@ -82,9 +96,6 @@ open class FirebaseTest<T : BaseActivity<*,*>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getEmail(): String? {
|
fun getEmail(): String? {
|
||||||
firebaseAuthSource.getUser()?.email?.let {
|
return firebaseAuthSource.getUser()?.email ?: email
|
||||||
return it
|
|
||||||
}
|
|
||||||
return email
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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<String>) {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,8 +3,12 @@ package h_mal.appttude.com.driver
|
|||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.google.gson.reflect.TypeToken
|
import com.google.gson.reflect.TypeToken
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
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.RequestBody.Companion.toRequestBody
|
||||||
|
import okhttp3.Response
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
import kotlin.coroutines.resumeWithException
|
import kotlin.coroutines.resumeWithException
|
||||||
|
|||||||
@@ -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<SignUpResponse>
|
||||||
|
|
||||||
|
@PUT("v1/accounts:signInWithPassword")
|
||||||
|
suspend fun signInWithPassword(@Body request: SignUpRequest): Response<SignUpResponse>
|
||||||
|
|
||||||
|
@PUT("v1/accounts:sendOobCode")
|
||||||
|
suspend fun sendOobCode(@Body request: Map<String, String>): Response<OobCodeResponse>
|
||||||
|
|
||||||
|
@PUT("v1/accounts:resetPassword")
|
||||||
|
suspend fun resetPassword(@Body request: ResetPasswordRequest): Response<ResetPasswordResponse>
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
)
|
||||||
|
|
||||||
@@ -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
|
||||||
|
)
|
||||||
|
|
||||||
@@ -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
|
||||||
|
)
|
||||||
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package h_mal.appttude.com.driver.firebase.model
|
||||||
|
|
||||||
|
data class SignUpRequest(
|
||||||
|
val password: String? = null,
|
||||||
|
val email: String? = null
|
||||||
|
)
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package h_mal.appttude.com.driver.firebase
|
package h_mal.appttude.com.driver.firebase.model
|
||||||
|
|
||||||
data class SignUpResponse(
|
data class SignUpResponse(
|
||||||
val expiresIn: String? = null,
|
val expiresIn: String? = null,
|
||||||
@@ -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<View>() {
|
||||||
|
override fun describeTo(description: Description?) {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun matches(actual: Any?): Boolean {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<View> = setConstraints()
|
||||||
|
|
||||||
|
override fun perform(uiController: UiController?, view: View?) {
|
||||||
|
setPerform(uiController, view)
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun setDescription(): String? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun setConstraints(): Matcher<View> {
|
||||||
|
return isAssignableFrom(View::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun setPerform(uiController: UiController?, view: View?) { }
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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<String>): 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<String>) {
|
||||||
|
filePaths.forEach { addItem(createClipItem(it)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<View>): ViewAction {
|
||||||
|
|
||||||
|
return object : ViewAction {
|
||||||
|
|
||||||
|
override fun getConstraints(): Matcher<View> = 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<View> = 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<View> {
|
||||||
|
return object : BaseMatcher<View>() {
|
||||||
|
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<View>,
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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(".", "-")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package h_mal.appttude.com.driver.robots
|
package h_mal.appttude.com.driver.robots
|
||||||
|
|
||||||
import h_mal.appttude.com.driver.BaseTestRobot
|
import h_mal.appttude.com.driver.BaseTestRobot
|
||||||
|
import h_mal.appttude.com.driver.PASSWORD
|
||||||
import h_mal.appttude.com.driver.R
|
import h_mal.appttude.com.driver.R
|
||||||
|
|
||||||
|
|
||||||
@@ -21,4 +22,11 @@ class LoginRobot : BaseTestRobot() {
|
|||||||
|
|
||||||
fun checkPasswordError(err: String) = checkErrorOnTextEntry(R.id.password, err)
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -8,17 +8,17 @@ class RegisterRobot : BaseTestRobot() {
|
|||||||
|
|
||||||
fun setName(name: String) = fillEditText(R.id.name_register, name)
|
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 setPassword(pass: String) = fillEditText(R.id.password_top, pass)
|
||||||
|
|
||||||
fun setPasswordConfirm(pass: String) = fillEditText(R.id.password_bottom, 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 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)
|
fun checkPasswordError(err: String) = checkErrorOnTextEntry(R.id.password_top, err)
|
||||||
|
|
||||||
@@ -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)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<CustomViewHolder<*>>(R.id.recycler_view, anyText)
|
||||||
|
|
||||||
|
fun clickOnDriverIdentifier(anyText: String) =
|
||||||
|
clickSubViewInRecycler<CustomViewHolder<*>>(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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>(MainActivity::class.java) {
|
||||||
|
override fun beforeLaunch() {
|
||||||
|
runBlocking {
|
||||||
|
login(ADMIN_EMAIL, PASSWORD)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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>(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()
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,11 +1,31 @@
|
|||||||
package h_mal.appttude.com.driver.robots
|
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.BaseTestRobot
|
||||||
import h_mal.appttude.com.driver.R
|
import h_mal.appttude.com.driver.R
|
||||||
|
|
||||||
fun home(func: HomeRobot.() -> Unit) = HomeRobot().apply { func() }
|
fun home(func: HomeRobot.() -> Unit) = HomeRobot().apply { func() }
|
||||||
class HomeRobot : BaseTestRobot() {
|
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)
|
||||||
}
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user