From 1e528617f2ae61cae2788e5bb15f57ae8b53a40e Mon Sep 17 00:00:00 2001 From: hmalik144 Date: Fri, 18 Aug 2023 21:26:21 +0100 Subject: [PATCH] Storage permission dispatcher (#33) - storage permissions request updated - test suite expanded --- .circleci/config.yml | 68 +++++++---- .gitignore | 2 + app/build.gradle | 6 + .../androidTest/assets/driver_details.json | 9 ++ .../androidTest/assets/drivers_license.json | 5 + .../androidTest/assets/insurance_details.json | 7 ++ app/src/androidTest/assets/log_book.json | 4 + app/src/androidTest/assets/mot_details.json | 4 + .../assets/private_hire_license.json | 5 + .../assets/private_hire_vehicle.json | 5 + .../androidTest/assets/vehicle_details.json | 11 ++ .../appttude/com/driver/BaseTestRobot.kt | 52 +++++---- .../h_mal/appttude/com/driver/BaseUiTest.kt | 72 ++++++------ .../appttude/com/driver/CustomViewMatchers.kt | 35 +++--- .../h_mal/appttude/com/driver/FormRobot.kt | 76 +++++++++---- .../com/driver/helpers/BaseMatcher.kt | 21 ++-- .../appttude/com/driver/helpers/Constants.kt | 15 +-- .../appttude/com/driver/helpers/DataHelper.kt | 5 +- .../com/driver/helpers/EspressoHelper.kt | 46 ++++++++ .../com/driver/helpers/SnapshotRule.kt | 1 - .../com/driver/untiTests}/DateUtilsTest.kt | 21 +++- .../appttude/com/driver/robots/DeleteRobot.kt | 5 +- .../com/driver/robots/UpdateEmailRobot.kt | 5 +- .../com/driver/robots/UpdatePasswordRobot.kt | 5 +- .../com/driver/robots/UpdateProfileRobot.kt | 10 +- .../robots/driver/DriversLicenseRobot.kt | 23 ++-- .../robots/driver/DriversProfileRobot.kt | 47 ++++---- .../robots/driver/PrivateHireLicenseRobot.kt | 25 ++-- .../driver/robots/vehicle/InsuranceRobot.kt | 23 ++-- .../com/driver/robots/vehicle/LogbookRobot.kt | 20 ++-- .../com/driver/robots/vehicle/MOTRobot.kt | 19 ++-- .../vehicle/PrivateHireVehicleLicenseRobot.kt | 26 +++-- .../robots/vehicle/VehicleProfileRobot.kt | 73 ++++++------ .../tests/newUser/DataSubmissionTest.kt | 52 +++++++++ .../driver/tests/newUser/DriverProfileTest.kt | 13 +++ .../newUser/SubmitNewDataActivityTest.kt | 37 ------ .../tests/newUser/SubmitNewDriverDataTest.kt | 54 +++++++++ .../tests/newUser/SubmitNewVehicleDataTest.kt | 80 +++++++++++++ .../tests/newUser/VehicleProfileTest.kt | 13 +++ .../ApplicationViewModelFactory.kt | 1 - .../driver/application/DriverApplication.kt | 10 -- .../appttude/com/driver/ui/HomeFragment.kt | 6 +- .../ui/driverprofile/DriverLicenseFragment.kt | 2 - .../ui/driverprofile/DriverProfileFragment.kt | 4 +- .../PrivateHireLicenseFragment.kt | 2 - .../ui/vehicleprofile/InsuranceFragment.kt | 2 - .../ui/vehicleprofile/LogbookFragment.kt | 2 - .../driver/ui/vehicleprofile/MotFragment.kt | 2 - .../PrivateHireVehicleFragment.kt | 2 - .../vehicleprofile/VehicleProfileFragment.kt | 2 - app/src/main/AndroidManifest.xml | 4 +- .../com/driver/application/BaseApplication.kt | 8 ++ .../appttude/com/driver/base/BaseActivity.kt | 9 +- .../com/driver/base/BaseFirebaseAdapter.kt | 1 + .../appttude/com/driver/base/BaseFragment.kt | 79 ------------- .../driver/base/DataSubmissionBaseFragment.kt | 32 ++---- .../com/driver/base/DrawerActivity.kt | 2 +- .../com/driver/base/ImageSelectorFragment.kt | 107 ++++++++++++++++++ .../driver/data/prefs/PreferencesProvider.kt | 3 +- .../appttude/com/driver/dialogs/DateDialog.kt | 28 +---- .../com/driver/model/DriverProfile.kt | 2 +- .../com/driver/model/DriversLicense.kt | 2 +- .../appttude/com/driver/model/Insurance.kt | 2 +- .../appttude/com/driver/model/Logbook.kt | 2 +- .../h_mal/appttude/com/driver/model/Model.kt | 3 + .../h_mal/appttude/com/driver/model/Mot.kt | 2 +- .../com/driver/model/PrivateHireLicense.kt | 2 +- .../com/driver/model/PrivateHireVehicle.kt | 4 +- .../com/driver/model/VehicleProfile.kt | 2 +- .../appttude/com/driver/ui/.idea/.gitignore | 3 - .../appttude/com/driver/ui/.idea/dictionaries | 6 - .../appttude/com/driver/ui/.idea/kotlinc.xml | 6 - .../appttude/com/driver/ui/.idea/misc.xml | 11 -- .../appttude/com/driver/ui/.idea/modules.xml | 8 -- .../appttude/com/driver/ui/.idea/vcs.xml | 6 - .../ui/permission/DeclarationBuilder.kt | 18 +++ .../PermissionsDeclarationDialog.kt | 46 ++++++++ .../com/driver/ui/update/UpdateActivity.kt | 6 +- .../driver/ui/update/UpdateProfileFragment.kt | 23 +--- .../appttude/com/driver/utils/DateUtils.kt | 34 +++--- .../appttude/com/driver/utils/Extensions.kt | 4 +- .../com/driver/utils/FirebaseException.kt | 14 ++- .../com/driver/utils/FirebaseUtils.kt | 5 +- .../com/driver/utils/GenericsHelper.kt | 6 +- .../com/driver/utils/PermissionsUtils.kt | 7 -- .../main/res/drawable/baseline_check_24.xml | 13 ++- .../main/res/drawable/baseline_clear_24.xml | 13 ++- .../main/res/drawable/baseline_inbox_24.xml | 13 ++- .../drawable/ic_baseline_arrow_forward_24.xml | 10 +- .../ic_baseline_assignment_ind_24.xml | 10 +- .../drawable/ic_baseline_photo_library_24.xml | 10 +- app/src/main/res/layout/activity_login.xml | 2 +- app/src/main/res/layout/app_bar_main.xml | 4 +- .../res/layout/fragment_delete_profile.xml | 8 +- .../res/layout/fragment_driver_license.xml | 39 ++++--- .../res/layout/fragment_driver_profile.xml | 33 +++--- .../res/layout/fragment_forgot_password.xml | 4 +- .../main/res/layout/fragment_image_viewer.xml | 4 +- .../main/res/layout/fragment_insurance.xml | 14 +-- app/src/main/res/layout/fragment_logbook.xml | 36 +++--- app/src/main/res/layout/fragment_login.xml | 8 +- app/src/main/res/layout/fragment_mot.xml | 20 ++-- .../layout/fragment_private_hire_license.xml | 14 +-- .../layout/fragment_private_hire_vehicle.xml | 8 +- app/src/main/res/layout/fragment_register.xml | 29 ++--- .../main/res/layout/fragment_update_email.xml | 34 +++--- .../res/layout/fragment_update_password.xml | 28 ++--- .../res/layout/fragment_update_profile.xml | 12 +- .../res/layout/fragment_vehicle_setup.xml | 56 ++++----- .../res/layout/home_buttons_container.xml | 6 +- app/src/main/res/layout/nav_header_main.xml | 6 +- app/src/main/res/layout/splash_screen.xml | 6 +- app/src/main/res/layout/update_activity.xml | 2 +- .../res/layout/update_overview_fragment.xml | 16 +-- .../main/res/navigation/auth_navigation.xml | 2 +- .../java/driver/ExampleUnitTest.java | 17 --- storage.rules | 2 +- 117 files changed, 1188 insertions(+), 823 deletions(-) create mode 100644 app/src/androidTest/assets/driver_details.json create mode 100644 app/src/androidTest/assets/drivers_license.json create mode 100644 app/src/androidTest/assets/insurance_details.json create mode 100644 app/src/androidTest/assets/log_book.json create mode 100644 app/src/androidTest/assets/mot_details.json create mode 100644 app/src/androidTest/assets/private_hire_license.json create mode 100644 app/src/androidTest/assets/private_hire_vehicle.json create mode 100644 app/src/androidTest/assets/vehicle_details.json rename app/src/{testDebug/java/h_mal/appttude/com/driver/utils => androidTest/java/h_mal/appttude/com/driver/untiTests}/DateUtilsTest.kt (55%) create mode 100644 app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/DataSubmissionTest.kt create mode 100644 app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/DriverProfileTest.kt delete mode 100644 app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/SubmitNewDataActivityTest.kt create mode 100644 app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/SubmitNewDriverDataTest.kt create mode 100644 app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/SubmitNewVehicleDataTest.kt create mode 100644 app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/VehicleProfileTest.kt create mode 100644 app/src/main/java/h_mal/appttude/com/driver/base/ImageSelectorFragment.kt create mode 100644 app/src/main/java/h_mal/appttude/com/driver/model/Model.kt delete mode 100644 app/src/main/java/h_mal/appttude/com/driver/ui/.idea/.gitignore delete mode 100644 app/src/main/java/h_mal/appttude/com/driver/ui/.idea/dictionaries delete mode 100644 app/src/main/java/h_mal/appttude/com/driver/ui/.idea/kotlinc.xml delete mode 100644 app/src/main/java/h_mal/appttude/com/driver/ui/.idea/misc.xml delete mode 100644 app/src/main/java/h_mal/appttude/com/driver/ui/.idea/modules.xml delete mode 100644 app/src/main/java/h_mal/appttude/com/driver/ui/.idea/vcs.xml create mode 100644 app/src/main/java/h_mal/appttude/com/driver/ui/permission/DeclarationBuilder.kt create mode 100644 app/src/main/java/h_mal/appttude/com/driver/ui/permission/PermissionsDeclarationDialog.kt delete mode 100644 app/src/testDebug/java/driver/ExampleUnitTest.java diff --git a/.circleci/config.yml b/.circleci/config.yml index 60faab9..55e49f0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -20,16 +20,10 @@ commands: command: | echo "$GOOGLE_SERVICES_KEY" > "app/google-services.json" - android/restore-gradle-cache - build_gradle: - description: Build the gradle - steps: - - android/restore-gradle-cache - run: - name: Download Dependencies + name: allow gradle command: | sudo chmod +x ./gradlew - ./gradlew androidDependencies - - android/save-gradle-cache run_tests: description: run non-instrumentation tests for flavour specified parameters: @@ -38,11 +32,11 @@ commands: default: "Driver" steps: # The next step will run the unit tests - - build_gradle - run: name: Run non-instrumentation unit tests command: | - ./gradlew test<< parameters.flavour >>DebugUnitTest --continue + ./gradlew test<< parameters.flavour >>DebugUnitTest + - android/save-gradle-cache - store_artifacts: path: app/build/reports destination: reports @@ -53,10 +47,9 @@ commands: parameters: flavour: type: string - default: "AtlasWeather" + default: "Driver" steps: # Download and cache dependencies - - build_gradle - run: name: Setup subtree for test data command: | @@ -78,9 +71,7 @@ commands: 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-test-command: adb push driver_app_data/images /sdcard/Camera pre-emulator-wait-steps: # Start firebase emulator in the background while waiting to start testing - run: @@ -94,6 +85,13 @@ commands: paths: - ~/.cache/firebase/emulators/ key: emulator-cache-v1-{{ epoch }} + # store screenshots for failed ui tests + - when: + condition: on_fail + steps: + - store_artifacts: + path: app/build/outputs/connected_android_test_additional_output/ + destination: connected_android_test # store test reports - store_artifacts: path: app/build/reports/androidTests/connected @@ -128,7 +126,6 @@ commands: name: Setup playstore key command: | echo "$GOOGLE_PLAY_KEY" > "google-play-key.json" - - build_gradle - run: name: Run fastlane command to deploy to playstore command: | @@ -156,8 +153,23 @@ jobs: steps: # Checkout the code and its submodule as the first step. - setup_repo -# - run_tests: -# flavour: << parameters.flavour >> + - run_tests: + flavour: << parameters.flavour >> + run_instrumentation_test: + # Parameters used for determining + parameters: + flavour: + type: string + default: "Driver" + # These next lines define the Android machine image executor. + # See: https://circleci.com/docs/2.0/executor-types/ + executor: + name: android/android-machine + tag: 2023.05.1 + # Add steps to the job + # See: https://circleci.com/docs/2.0/configuration-reference/#steps + steps: + - setup_repo - run_ui_tests: flavour: << parameters.flavour >> deploy-to-playstore: @@ -187,6 +199,14 @@ workflows: branches: ignore: - main_admin + - run_instrumentation_test: + context: appttude + flavour: "Driver" + filters: + branches: + only: + - master + - main_driver - deploy-to-playstore: context: appttude flavour: "Driver" @@ -195,7 +215,7 @@ workflows: only: - main_driver requires: - - build-and-test + - run_instrumentation_test build-release-admin: jobs: - build-and-test: @@ -205,12 +225,20 @@ workflows: branches: ignore: - main_driver - - deploy-to-playstore: + - run_instrumentation_test: context: appttude flavour: "Admin" + filters: + branches: + only: + - master + - main_admin + - deploy-to-playstore: + context: appttude + flavour: "Driver" filters: branches: only: - main_admin requires: - - build-and-test \ No newline at end of file + - run_instrumentation_test \ No newline at end of file diff --git a/.gitignore b/.gitignore index ab59a65..a1f243b 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,5 @@ local # Firebase emulator database-debug.log firebase-debug.log +# Subtree +driver_app_data diff --git a/app/build.gradle b/app/build.gradle index 460167c..2f2cdc4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -166,4 +166,10 @@ dependencies { androidTestImplementation "com.squareup.retrofit2:converter-gson:$retrofit_version" / * screenshot library */ androidTestImplementation 'tools.fastlane:screengrab:2.1.1' + / * Permissions dispatcher * / + def dispatcher_ver = "4.9.2" + implementation "com.github.permissions-dispatcher:permissionsdispatcher:${dispatcher_ver}" + kapt "com.github.permissions-dispatcher:permissionsdispatcher-processor:${dispatcher_ver}" + / * Date utils * / + implementation 'net.danlew:android.joda:2.12.5' } diff --git a/app/src/androidTest/assets/driver_details.json b/app/src/androidTest/assets/driver_details.json new file mode 100644 index 0000000..e5bb1e0 --- /dev/null +++ b/app/src/androidTest/assets/driver_details.json @@ -0,0 +1,9 @@ +{ + "address": "123 test street update", + "dateFirst": "26/01/2019", + "dob": "26/01/1979", + "forenames": "Alex Smith", + "driverPic": "driver_profile_pic.jpg", + "ni": "NI 12 34 56 A", + "postcode": "EC1V 2AL" +} \ No newline at end of file diff --git a/app/src/androidTest/assets/drivers_license.json b/app/src/androidTest/assets/drivers_license.json new file mode 100644 index 0000000..2dd2ec9 --- /dev/null +++ b/app/src/androidTest/assets/drivers_license.json @@ -0,0 +1,5 @@ +{ + "licenseExpiry": "27/04/2019", + "licenseImageString": "driver_license_driver.jpg", + "licenseNumber": "FARME100165AB5EW" +} \ No newline at end of file diff --git a/app/src/androidTest/assets/insurance_details.json b/app/src/androidTest/assets/insurance_details.json new file mode 100644 index 0000000..3911458 --- /dev/null +++ b/app/src/androidTest/assets/insurance_details.json @@ -0,0 +1,7 @@ +{ + "expiryDate": "03/02/2019", + "insurerName": "Insurer", + "photoStrings": [ + "driver_insurance.jpg" + ] +} \ No newline at end of file diff --git a/app/src/androidTest/assets/log_book.json b/app/src/androidTest/assets/log_book.json new file mode 100644 index 0000000..3cd9971 --- /dev/null +++ b/app/src/androidTest/assets/log_book.json @@ -0,0 +1,4 @@ +{ + "photoString": "driver_logbook.jpg", + "v5cnumber": "NJ59NTV" +} \ No newline at end of file diff --git a/app/src/androidTest/assets/mot_details.json b/app/src/androidTest/assets/mot_details.json new file mode 100644 index 0000000..1c21e75 --- /dev/null +++ b/app/src/androidTest/assets/mot_details.json @@ -0,0 +1,4 @@ +{ + "motExpiry": "11/06/2019", + "motImageString": "driver_mot.jpg" +} \ No newline at end of file diff --git a/app/src/androidTest/assets/private_hire_license.json b/app/src/androidTest/assets/private_hire_license.json new file mode 100644 index 0000000..d266591 --- /dev/null +++ b/app/src/androidTest/assets/private_hire_license.json @@ -0,0 +1,5 @@ +{ + "phExpiry": "27/04/2019", + "phImageString": "driver_license_private_hire.jpg", + "phNumber": "987651" +} \ No newline at end of file diff --git a/app/src/androidTest/assets/private_hire_vehicle.json b/app/src/androidTest/assets/private_hire_vehicle.json new file mode 100644 index 0000000..7bfcbfa --- /dev/null +++ b/app/src/androidTest/assets/private_hire_vehicle.json @@ -0,0 +1,5 @@ +{ + "phCarExpiry": "28/01/2019", + "phCarImageString": "driver_license_private_hire_car.jpg", + "phCarNumber": "4602060501" +} \ No newline at end of file diff --git a/app/src/androidTest/assets/vehicle_details.json b/app/src/androidTest/assets/vehicle_details.json new file mode 100644 index 0000000..abb1dbc --- /dev/null +++ b/app/src/androidTest/assets/vehicle_details.json @@ -0,0 +1,11 @@ +{ + "colour": "Black", + "keeperAddress": "483 Green lanes London", + "keeperName": "Adam Cars Ltd", + "keeperPostCode": "N13 4BS", + "make": "Toyota", + "model": "Prius", + "reg": "NG59ERY", + "seized": false, + "startDate": "04/02/2019" +} \ No newline at end of file diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/BaseTestRobot.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/BaseTestRobot.kt index bf99b98..e2730fb 100644 --- a/app/src/androidTest/java/h_mal/appttude/com/driver/BaseTestRobot.kt +++ b/app/src/androidTest/java/h_mal/appttude/com/driver/BaseTestRobot.kt @@ -7,7 +7,7 @@ import android.content.res.Resources import android.net.Uri import android.view.View import android.widget.DatePicker -import android.widget.ListView +import androidx.annotation.IdRes import androidx.annotation.StringRes import androidx.recyclerview.widget.RecyclerView.ViewHolder import androidx.test.espresso.Espresso.onData @@ -17,13 +17,13 @@ import androidx.test.espresso.ViewAction import androidx.test.espresso.ViewInteraction import androidx.test.espresso.action.ViewActions import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.action.ViewActions.scrollTo import androidx.test.espresso.action.ViewActions.swipeDown import androidx.test.espresso.assertion.ViewAssertions.matches 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 @@ -41,34 +41,40 @@ import java.io.File @SuppressWarnings("unused") open class BaseTestRobot { - fun fillEditText(resId: Int, text: String?): ViewInteraction = + fun fillEditText(@IdRes resId: Int, text: String?): ViewInteraction = onView(withId(resId)).perform( ViewActions.replaceText(text), ViewActions.closeSoftKeyboard() ) - fun clickButton(resId: Int): ViewInteraction = + fun scrollAndFillEditText(@IdRes resId: Int, text: String?): ViewInteraction = + onView(withId(resId)).perform( + scrollTo(), + ViewActions.replaceText(text), + ViewActions.closeSoftKeyboard() + ) + + fun clickButton(@IdRes resId: Int): ViewInteraction = onView((withId(resId))).perform(click()) - fun matchView(resId: Int): ViewInteraction = onView(withId(resId)) + fun matchView(@IdRes resId: Int): ViewInteraction = onView(withId(resId)) - fun matchViewWaitFor(resId: Int): ViewInteraction = waitForView(withId(resId)) + fun matchViewWaitFor(@IdRes resId: Int): ViewInteraction = waitForView(withId(resId)) fun matchText(viewInteraction: ViewInteraction, text: String): ViewInteraction = viewInteraction .check(matches(withText(text))) - fun matchText(viewId: Int, textId: Int): ViewInteraction = onView(withId(viewId)) - .check(matches(withText(textId))) + fun matchText(@StringRes stringId:Int): ViewInteraction = onView(withText(stringId)) - fun matchText(resId: Int, text: String): ViewInteraction = matchText(matchView(resId), text) + fun matchText(@IdRes resId: Int, text: String): ViewInteraction = matchText(matchView(resId), text) - fun clickListItem(listRes: Int, position: Int) { + fun clickListItem(@IdRes listRes: Int, position: Int) { onData(anything()) .inAdapterView(allOf(withId(listRes))) .atPosition(position).perform(click()) } - fun scrollToRecyclerItem(recyclerId: Int, text: String): ViewInteraction? { + fun scrollToRecyclerItem(@IdRes recyclerId: Int, text: String): ViewInteraction? { return matchView(recyclerId) .perform( // scrollTo will fail the test if no item matches. @@ -78,7 +84,7 @@ open class BaseTestRobot { ) } - fun scrollToRecyclerItem(recyclerId: Int, resIdForString: Int): ViewInteraction? { + fun scrollToRecyclerItem(@IdRes recyclerId: Int, resIdForString: Int): ViewInteraction? { return matchView(recyclerId) .perform( // scrollTo will fail the test if no item matches. @@ -88,7 +94,7 @@ open class BaseTestRobot { ) } - fun scrollToRecyclerItemByPosition(recyclerId: Int, position: Int): ViewInteraction? { + fun scrollToRecyclerItemByPosition(@IdRes recyclerId: Int, position: Int): ViewInteraction? { return matchView(recyclerId) .perform( // scrollTo will fail the test if no item matches. @@ -96,7 +102,7 @@ open class BaseTestRobot { ) } - fun clickViewInRecycler(recyclerId: Int, text: String) { + fun clickViewInRecycler(@IdRes recyclerId: Int, text: String) { matchView(recyclerId) .perform( // scrollTo will fail the test if no item matches. @@ -104,7 +110,7 @@ open class BaseTestRobot { ) } - fun clickViewInRecycler(recyclerId: Int, resIdForString: Int) { + fun clickViewInRecycler(@IdRes recyclerId: Int, resIdForString: Int) { matchView(recyclerId) .perform( // scrollTo will fail the test if no item matches. @@ -112,7 +118,7 @@ open class BaseTestRobot { ) } - fun clickSubViewInRecycler(recyclerId: Int, text: String, subView: Int) { + fun clickSubViewInRecycler(@IdRes recyclerId: Int, text: String, subView: Int) { scrollToRecyclerItem(recyclerId, text) ?.perform( // scrollTo will fail the test if no item matches. @@ -128,13 +134,13 @@ open class BaseTestRobot { ) } - fun checkErrorOnTextEntry(resId: Int, errorMessage: String): ViewInteraction = + fun checkErrorOnTextEntry(@IdRes resId: Int, errorMessage: String): ViewInteraction = onView(withId(resId)).check(matches(checkErrorMessage(errorMessage))) - fun checkImageViewHasImage(resId: Int): ViewInteraction = + fun checkImageViewDoesNotHaveDefaultImage(@IdRes resId: Int): ViewInteraction = onView(withId(resId)).check(matches(checkImage())) - fun swipeDown(resId: Int): ViewInteraction = + fun swipeDown(@IdRes resId: Int): ViewInteraction = onView(withId(resId)).perform(swipeDown()) fun getStringFromResource(@StringRes resId: Int): String = @@ -150,12 +156,12 @@ open class BaseTestRobot { ) } - fun selectSingleImageFromGallery(filePath: FormRobot.FilePath, openSelector: () -> Unit) { + fun selectSingleImageFromGallery(filePath: String, 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))) + resultData.data = Uri.fromFile(File("/sdcard/Camera/", 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) @@ -164,7 +170,7 @@ open class BaseTestRobot { Intents.release() } - fun selectMultipleImageFromGallery(filePaths: Array, openSelector: () -> Unit) { + fun selectMultipleImageFromGallery(filePaths: List, openSelector: () -> Unit) { Intents.init() // Build the result to return when the activity is launched. val resultData = Intent() @@ -172,7 +178,7 @@ open class BaseTestRobot { 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) + intending(hasAction(Intent.ACTION_GET_CONTENT)).respondWith(result) openSelector() Intents.release() diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/BaseUiTest.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/BaseUiTest.kt index 376fdf3..1dd9acc 100644 --- a/app/src/androidTest/java/h_mal/appttude/com/driver/BaseUiTest.kt +++ b/app/src/androidTest/java/h_mal/appttude/com/driver/BaseUiTest.kt @@ -3,38 +3,41 @@ package h_mal.appttude.com.driver import android.Manifest import android.R import android.app.Activity -import android.content.Context -import android.os.Build import android.view.View -import android.view.WindowManager import androidx.annotation.StringRes import androidx.test.core.app.ActivityScenario -import androidx.test.espresso.* import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.IdlingRegistry +import androidx.test.espresso.IdlingResource +import androidx.test.espresso.UiController +import androidx.test.espresso.ViewAction import androidx.test.espresso.assertion.ViewAssertions.matches -import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.isRoot +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation import androidx.test.rule.GrantPermissionRule +import com.google.gson.Gson import h_mal.appttude.com.driver.base.BaseActivity import h_mal.appttude.com.driver.helpers.BaseViewAction import h_mal.appttude.com.driver.helpers.SnapshotRule import org.hamcrest.CoreMatchers -import org.hamcrest.Description import org.hamcrest.Matcher -import org.hamcrest.TypeSafeMatcher import org.hamcrest.core.AllOf import org.junit.After import org.junit.Before -import org.junit.ClassRule import org.junit.Rule import tools.fastlane.screengrab.Screengrab import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy import tools.fastlane.screengrab.locale.LocaleTestRule +import java.io.BufferedReader open class BaseUiTest>( private val activity: Class ) { + val gson by lazy { Gson() } private lateinit var mActivityScenarioRule: ActivityScenario private var mIdlingResource: IdlingResource? = null @@ -42,7 +45,7 @@ open class BaseUiTest>( private lateinit var currentActivity: Activity @get:Rule - var permissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE) + var permissionRule = GrantPermissionRule.grant(Manifest.permission.READ_EXTERNAL_STORAGE) @get:Rule var snapshotRule: SnapshotRule = SnapshotRule() @@ -59,8 +62,8 @@ open class BaseUiTest>( mActivityScenarioRule.onActivity { mIdlingResource = it.getIdlingResource()!! IdlingRegistry.getInstance().register(mIdlingResource) - afterLaunch(it) } + afterLaunch() } @After @@ -87,36 +90,7 @@ open class BaseUiTest>( } open fun beforeLaunch() {} - open fun afterLaunch(context: Context) {} - - - @Suppress("DEPRECATION") - fun checkToastMessage(message: String) { - onView(withText(message)).inRoot(object : TypeSafeMatcher() { - override fun describeTo(description: Description?) { - description?.appendText("is toast") - } - - override fun matchesSafely(root: Root): Boolean { - root.run { - if (windowLayoutParams.get().type == WindowManager.LayoutParams.TYPE_TOAST) { - decorView.run { - if (windowToken === applicationWindowToken) { - // windowToken == appToken means this window isn't contained by any other windows. - // if it was a window for an activity, it would have TYPE_BASE_APPLICATION. - return true - } - } - } - } - return false - } - } - ).check(matches(isDisplayed())) - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { - waitFor(3500) - } - } + open fun afterLaunch() {} fun checkSnackBarDisplayedByMessage(message: String) { onView( @@ -138,4 +112,22 @@ open class BaseUiTest>( }) return currentActivity } + + fun readDataFromAsset(fileName: String, clazz: Class): T { + val iStream = + getInstrumentation().context.assets.open("$fileName.json") + val data = iStream.bufferedReader().use(BufferedReader::readText) + return gson.fromJson(data, clazz) + } + + inline fun readDataFromAsset(fileName: String): M { + val iStream = + getInstrumentation().context.assets.open("$fileName.json") + val data = iStream.bufferedReader().use(BufferedReader::readText) + return fromJson(data) + } + + inline fun fromJson(json: String) + = gson.fromJson(json, M::class.java) + } \ No newline at end of file diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/CustomViewMatchers.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/CustomViewMatchers.kt index 09472ef..43ac5c2 100644 --- a/app/src/androidTest/java/h_mal/appttude/com/driver/CustomViewMatchers.kt +++ b/app/src/androidTest/java/h_mal/appttude/com/driver/CustomViewMatchers.kt @@ -5,41 +5,32 @@ import android.view.View import android.widget.EditText import android.widget.ImageView import com.google.android.material.textfield.TextInputLayout -import org.hamcrest.Description +import h_mal.appttude.com.driver.helpers.BaseMatcher import org.hamcrest.Matcher -import org.hamcrest.TypeSafeMatcher /** * Matcher for testing error of TextInputLayout */ -fun checkErrorMessage(expectedErrorText: String): Matcher { - return object : TypeSafeMatcher() { - override fun matchesSafely(view: View?): Boolean { - if (view is EditText) { - return view.error.toString() == expectedErrorText +fun checkErrorMessage(expectedErrorText: String): Matcher { + return object : BaseMatcher() { + override fun match(item: View): Boolean { + if (item is EditText) { + return item.error.toString() == expectedErrorText } - if (view !is TextInputLayout) return false + if (item !is TextInputLayout) return false - val error = view.error ?: return false + val error = item.error ?: return false return expectedErrorText == error.toString() } - - override fun describeTo(d: Description?) {} } } -fun checkImage(): Matcher { - return object : TypeSafeMatcher() { - override fun matchesSafely(view: View?): Boolean { - if (view is ImageView) { - return hasImage(view) - } - return false - } - - override fun describeTo(d: Description?) {} +@Suppress("UNCHECKED_CAST") +fun checkImage(): Matcher { + return object: BaseMatcher() { + override fun match(item: ImageView): Boolean = hasImage(item) private fun hasImage(view: ImageView): Boolean { val drawable = view.drawable @@ -49,6 +40,6 @@ fun checkImage(): Matcher { } return hasImage } - } + } as Matcher } diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/FormRobot.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/FormRobot.kt index 24f2967..4cd967a 100644 --- a/app/src/androidTest/java/h_mal/appttude/com/driver/FormRobot.kt +++ b/app/src/androidTest/java/h_mal/appttude/com/driver/FormRobot.kt @@ -1,13 +1,27 @@ package h_mal.appttude.com.driver import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.ViewInteraction import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.action.ViewActions.scrollTo +import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom import androidx.test.espresso.matcher.ViewMatchers.withId -import h_mal.appttude.com.driver.helpers.getImagePath +import h_mal.appttude.com.driver.helpers.EspressoHelper.trying +import h_mal.appttude.com.driver.model.Model +import org.hamcrest.CoreMatchers.allOf +import java.time.LocalDate +import java.time.format.DateTimeFormatter -open class FormRobot : BaseTestRobot() { - fun submit() = clickButton(R.id.submit) +open class FormRobot : BaseTestRobot() { + + fun submit() = onView( + allOf( + withId(R.id.submit), + isAssignableFrom(com.google.android.material.button.MaterialButton::class.java) + ) + ).perform(click()) + fun setDate(datePickerLaunchViewId: Int, year: Int, monthOfYear: Int, dayOfMonth: Int) { onView(withId(datePickerLaunchViewId)).perform(click()) selectDateInPicker(year, monthOfYear, dayOfMonth) @@ -15,32 +29,50 @@ open class FormRobot : BaseTestRobot() { onView(withId(android.R.id.button1)).perform(click()) } - fun selectSingleImage(imagePickerLauncherViewId: Int, filePath: FilePath) { - selectSingleImageFromGallery(filePath) { - onView(withId(imagePickerLauncherViewId)).perform(click()) - } + fun setDate(datePickerLaunchViewId: Int, dateString: String) { + onView(withId(datePickerLaunchViewId)).perform(click()) + val date = LocalDate.parse(dateString, DateTimeFormatter.ofPattern("dd/MM/yyyy")) + selectDateInPicker(date.year, date.monthValue, date.dayOfMonth) // click ok in date picker + onView(withId(android.R.id.button1)).perform(click()) } - fun selectMultipleImage(imagePickerLauncherViewId: Int, filePaths: Array) { - selectMultipleImageFromGallery(filePaths) { + fun scrollAndSetDate(datePickerLaunchViewId: Int, dateString: String) { + onView(withId(datePickerLaunchViewId)).perform(scrollTo(), click()) + val date = LocalDate.parse(dateString, DateTimeFormatter.ofPattern("dd/MM/yyyy")) + selectDateInPicker(date.year, date.monthValue, date.dayOfMonth) + // click ok in date picker + onView(withId(android.R.id.button1)).perform(click()) + } + + fun selectSingleImage(imagePickerLauncherViewId: Int, fileName: String) { + selectSingleImageFromGallery(fileName) { 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) - } + fun selectSingleImage(imagePickerViewInteraction: ViewInteraction, fileName: String) { + selectSingleImageFromGallery(fileName) { + imagePickerViewInteraction.perform(click()) } } + + fun selectMultipleImage(imagePickerLauncherViewId: Int, filePaths: List) { + selectMultipleImageFromGallery(filePaths.map { "/sdcard/Camera/$it" }) { + onView(withId(imagePickerLauncherViewId)).perform(click()) + } + } + + open fun submitForm(data: T) { + (trying { + onView(withId(R.id.submit)).perform(scrollTo()) + } ?: onView(withId(R.id.submit))).perform(click()) + } + + open fun validateSubmission(data: T) {} + + open fun submitAndValidate(data: T) { + submitForm(data) + validateSubmission(data) + } } \ No newline at end of file diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/BaseMatcher.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/BaseMatcher.kt index b13e895..1b59949 100644 --- a/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/BaseMatcher.kt +++ b/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/BaseMatcher.kt @@ -1,17 +1,22 @@ package h_mal.appttude.com.driver.helpers -import android.view.View -import org.hamcrest.BaseMatcher import org.hamcrest.Description +import org.hamcrest.TypeSafeMatcher -class BaseMatcher: BaseMatcher() { - override fun describeTo(description: Description?) { - TODO("Not yet implemented") +open class BaseMatcher: TypeSafeMatcher() { + override fun describeTo(description: Description?) { } + + override fun describeMismatchSafely(item: T, mismatchDescription: Description?) { + describe(item, mismatchDescription) } - override fun matches(actual: Any?): Boolean { - TODO("Not yet implemented") - } + override fun matchesSafely(item: T): Boolean = match(item) + + open fun match(item: T): Boolean { return false } + + open fun describe(item: T, mismatchDescription: Description?) { + super.describeMismatchSafely(item, mismatchDescription) + } } \ No newline at end of file diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/Constants.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/Constants.kt index 31ba4f7..54f30c1 100644 --- a/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/Constants.kt +++ b/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/Constants.kt @@ -1,14 +1 @@ -package h_mal.appttude.com.driver.helpers - -import android.os.Environment -import java.io.File - -/** - * File paths for images on device - */ -fun getImagePath(imageConst: String): String { - return File( - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), - "/Camera/images/$imageConst" - ).absolutePath -} \ No newline at end of file +package h_mal.appttude.com.driver.helpers \ No newline at end of file diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/DataHelper.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/DataHelper.kt index bc2e262..42ccbb1 100644 --- a/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/DataHelper.kt +++ b/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/DataHelper.kt @@ -18,10 +18,9 @@ object DataHelper { fun createClipData(filePath: String) = createClipData(createClipItem(filePath)) - fun createClipData(filePaths: Array): ClipData { + fun createClipData(filePaths: List): ClipData { val clipData = createClipData(filePaths[0]) - val remainingFiles = filePaths.copyOfRange(1, filePaths.size - 1) - clipData.addFilePaths(remainingFiles) + filePaths.filterIndexed { i, _ -> i > 0 }.let { clipData.addFilePaths(it.toTypedArray()) } return clipData } diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/EspressoHelper.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/EspressoHelper.kt index 08ade1e..7add2fb 100644 --- a/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/EspressoHelper.kt +++ b/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/EspressoHelper.kt @@ -120,4 +120,50 @@ object EspressoHelper { throw Exception("Error finding a view matching $viewMatcher") } + + /** + * try and perform a view interaction for + * @param waitMillis at intervals of + * @param waitMillisPerTry, + * upon failure to locate an element, it will return null + * + */ + fun ViewInteraction.tryPerform( + vararg viewActions: ViewAction, + waitMillis: Int = 1000, + waitMillisPerTry: Long = 200, + ): 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 + return perform(*viewActions) + + } catch (e: Exception) { + + if (tries == maxTries) { + throw e + } + sleep(waitMillisPerTry) + } + + return null + } + + fun trying(action: () -> T): T? { + return try { + val result = action.invoke() + result + }catch (_: Exception) { + null + } + } } \ No newline at end of file diff --git a/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/SnapshotRule.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/SnapshotRule.kt index 90a9911..018611e 100644 --- a/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/SnapshotRule.kt +++ b/app/src/androidTest/java/h_mal/appttude/com/driver/helpers/SnapshotRule.kt @@ -3,7 +3,6 @@ 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. diff --git a/app/src/testDebug/java/h_mal/appttude/com/driver/utils/DateUtilsTest.kt b/app/src/androidTest/java/h_mal/appttude/com/driver/untiTests/DateUtilsTest.kt similarity index 55% rename from app/src/testDebug/java/h_mal/appttude/com/driver/utils/DateUtilsTest.kt rename to app/src/androidTest/java/h_mal/appttude/com/driver/untiTests/DateUtilsTest.kt index e4ecf26..6a7ec1c 100644 --- a/app/src/testDebug/java/h_mal/appttude/com/driver/utils/DateUtilsTest.kt +++ b/app/src/androidTest/java/h_mal/appttude/com/driver/untiTests/DateUtilsTest.kt @@ -1,11 +1,24 @@ -package h_mal.appttude.com.driver.utils +package h_mal.appttude.com.driver.untiTests +import androidx.startup.AppInitializer +import androidx.test.platform.app.InstrumentationRegistry +import h_mal.appttude.com.driver.utils.DateUtils import h_mal.appttude.com.driver.utils.DateUtils.convertDateStringDatePattern -import org.junit.Assert.* +import net.danlew.android.joda.JodaTimeInitializer +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Before import org.junit.Test class DateUtilsTest { + @Before + fun setup() { + AppInitializer.getInstance(InstrumentationRegistry.getInstrumentation().context.applicationContext) + .initializeComponent(JodaTimeInitializer::class.java) + } + @Test fun test_getDateTimeStamp() { val regex1 = "[0-9]{8}_[0-9]{6}".toRegex() @@ -31,6 +44,8 @@ class DateUtilsTest { } @Test - fun test_parseCalenderIntoDateString() { + fun test_getDateString() { + val date = DateUtils.getDateString(2019, 8, 1) + assertEquals(date, "01/08/2019") } } \ No newline at end of file diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/DeleteRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/DeleteRobot.kt index 9df821e..c909ea3 100644 --- a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/DeleteRobot.kt +++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/DeleteRobot.kt @@ -1,11 +1,12 @@ package h_mal.appttude.com.driver.robots -import h_mal.appttude.com.driver.FormRobot +import h_mal.appttude.com.driver.BaseTestRobot import h_mal.appttude.com.driver.R fun delete(func: DeleteRobot.() -> Unit) = DeleteRobot().apply { func() } -class DeleteRobot : FormRobot() { +class DeleteRobot : BaseTestRobot() { + fun submit() = clickButton(R.id.submit) fun enterEmail(email: String) = fillEditText(R.id.email_update, email) fun enterPassword(password: String) = fillEditText(R.id.password_top, password) diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/UpdateEmailRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/UpdateEmailRobot.kt index 5170234..a45e527 100644 --- a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/UpdateEmailRobot.kt +++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/UpdateEmailRobot.kt @@ -1,11 +1,12 @@ package h_mal.appttude.com.driver.robots -import h_mal.appttude.com.driver.FormRobot +import h_mal.appttude.com.driver.BaseTestRobot import h_mal.appttude.com.driver.R fun updateEmail(func: UpdateEmailRobot.() -> Unit) = UpdateEmailRobot().apply { func() } -class UpdateEmailRobot : FormRobot() { +class UpdateEmailRobot : BaseTestRobot() { + fun submit() = clickButton(R.id.submit) 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) diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/UpdatePasswordRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/UpdatePasswordRobot.kt index b3b44f0..d5079ca 100644 --- a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/UpdatePasswordRobot.kt +++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/UpdatePasswordRobot.kt @@ -1,11 +1,12 @@ package h_mal.appttude.com.driver.robots -import h_mal.appttude.com.driver.FormRobot +import h_mal.appttude.com.driver.BaseTestRobot import h_mal.appttude.com.driver.R fun updatePassword(func: UpdatePasswordRobot.() -> Unit) = UpdatePasswordRobot().apply { func() } -class UpdatePasswordRobot : FormRobot() { +class UpdatePasswordRobot : BaseTestRobot() { + fun submit() = clickButton(R.id.submit) 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) diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/UpdateProfileRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/UpdateProfileRobot.kt index 9e4e15a..816c0c0 100644 --- a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/UpdateProfileRobot.kt +++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/UpdateProfileRobot.kt @@ -1,16 +1,18 @@ package h_mal.appttude.com.driver.robots -import h_mal.appttude.com.driver.FormRobot +import h_mal.appttude.com.driver.BaseTestRobot import h_mal.appttude.com.driver.R fun updateProfile(func: UpdateProfileRobot.() -> Unit) = UpdateProfileRobot().apply { func() } -class UpdateProfileRobot : FormRobot() { +class UpdateProfileRobot : BaseTestRobot() { + fun submit() = clickButton(R.id.submit) 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() + selectSingleImageFromGallery("driver_profile_pic") { + clickButton(R.id.profile_img) + } enterName(name) submit() } diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/driver/DriversLicenseRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/driver/DriversLicenseRobot.kt index 0c3270f..c1d3725 100644 --- a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/driver/DriversLicenseRobot.kt +++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/driver/DriversLicenseRobot.kt @@ -2,26 +2,23 @@ package h_mal.appttude.com.driver.robots.driver import h_mal.appttude.com.driver.FormRobot import h_mal.appttude.com.driver.R +import h_mal.appttude.com.driver.model.DriversLicense fun driversLicense(func: DriversLicenseRobot.() -> Unit) = DriversLicenseRobot().apply { func() } -class DriversLicenseRobot : FormRobot() { +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 enterLicenseExpiry(data: String) = setDate(R.id.lic_expiry, data) - 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() + override fun submitForm(data: DriversLicense) { + selectSingleImage(R.id.search_image, data.licenseImageString!!) + enterLicenseExpiry(data.licenseExpiry!!) + enterLicenseNumber(data.licenseNumber!!) + super.submitForm(data) } - fun validate() { - checkImageViewHasImage(R.id.driversli_img) - + override fun validateSubmission(data: DriversLicense) { + checkImageViewDoesNotHaveDefaultImage(R.id.driversli_img) } } \ No newline at end of file diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/driver/DriversProfileRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/driver/DriversProfileRobot.kt index da44a6a..05f9245 100644 --- a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/driver/DriversProfileRobot.kt +++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/driver/DriversProfileRobot.kt @@ -1,38 +1,39 @@ package h_mal.appttude.com.driver.robots.driver +import androidx.test.espresso.action.ViewActions.closeSoftKeyboard +import androidx.test.espresso.action.ViewActions.scrollTo import h_mal.appttude.com.driver.FormRobot import h_mal.appttude.com.driver.R +import h_mal.appttude.com.driver.model.DriverProfile fun driversProfile(func: DriversProfileRobot.() -> Unit) = DriversProfileRobot().apply { func() } -class DriversProfileRobot : FormRobot() { +class DriversProfileRobot : FormRobot() { fun enterName(name: String) = fillEditText(R.id.names_input, name) fun enterAddress(address: String) = fillEditText(R.id.address_input, address) fun enterPostcode(postcode: String) = fillEditText(R.id.postcode_input, postcode) - fun enterDateOfBirth(dob: String) = fillEditText(R.id.dob_input, dob) + fun enterDateOfBirth(date: String) = setDate(R.id.dob_input, date) + fun enterNINumber(niNumber: String) = fillEditText(R.id.ni_number, niNumber) - fun enterDateFirstAvailable(year: Int, monthOfYear: Int, dayOfMonth: Int) = - setDate(R.id.date_first, year, monthOfYear, dayOfMonth) + fun enterDateFirstAvailable(date: String) { + closeSoftKeyboard() + matchView(R.id.date_first).perform(scrollTo()) + setDate(R.id.date_first, date) + } - fun selectImage() = selectSingleImage(R.id.add_photo, FilePath.PROFILE_PIC) + override fun validateSubmission(data: DriverProfile) { + checkImageViewDoesNotHaveDefaultImage(R.id.driver_pic) + matchText(R.id.names_input, data.forenames!!) + } - fun submitForm( - name: String, - address: String, - postcode: String, - dob: String, - niNumber: String, - year: Int, - monthOfYear: Int, - dayOfMonth: Int - ) { - selectImage() - enterName(name) - enterAddress(address) - enterPostcode(postcode) - enterDateOfBirth(dob) - enterNINumber(niNumber) - enterDateFirstAvailable(year, monthOfYear, dayOfMonth) - submit() + override fun submitForm(data: DriverProfile) = data.run { + selectSingleImage(R.id.add_photo, driverPic!!) + enterName(forenames!!) + enterAddress(address!!) + enterPostcode(postcode!!) + enterDateOfBirth(dob!!) + enterNINumber(ni!!) + enterDateFirstAvailable(dateFirst!!) + super.submitForm(data) } } \ No newline at end of file diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/driver/PrivateHireLicenseRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/driver/PrivateHireLicenseRobot.kt index 6f5c9d1..e1829aa 100644 --- a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/driver/PrivateHireLicenseRobot.kt +++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/driver/PrivateHireLicenseRobot.kt @@ -2,22 +2,29 @@ package h_mal.appttude.com.driver.robots.driver import h_mal.appttude.com.driver.FormRobot import h_mal.appttude.com.driver.R +import h_mal.appttude.com.driver.model.PrivateHireLicense fun privateHireLicenseRobot(func: PrivateHireLicenseRobot.() -> Unit) = PrivateHireLicenseRobot().apply { func() } -class PrivateHireLicenseRobot : FormRobot() { +class PrivateHireLicenseRobot : FormRobot() { fun enterLicenseNumber(text: String) = fillEditText(R.id.ph_no, text) - fun enterLicenseExpiry(year: Int, monthOfYear: Int, dayOfMonth: Int) = - setDate(R.id.ph_expiry, year, monthOfYear, dayOfMonth) + fun enterLicenseExpiry(date: String) = setDate(R.id.ph_expiry, date) - fun selectImage() = selectSingleImage(R.id.uploadphlic, FilePath.PRIVATE_HIRE) + fun selectImage(fileName: String) = selectSingleImage(R.id.uploadphlic, fileName) - fun submitForm(licenseNumber: String, year: Int, monthOfYear: Int, dayOfMonth: Int) { - selectImage() - enterLicenseNumber(licenseNumber) - enterLicenseExpiry(year, monthOfYear, dayOfMonth) - submit() + override fun submitForm(data: PrivateHireLicense) { + selectImage(data.phImageString!!) + enterLicenseNumber(data.phNumber!!) + enterLicenseExpiry(data.phExpiry!!) + super.submitForm(data) } + + fun validate(data: PrivateHireLicense) { + checkImageViewDoesNotHaveDefaultImage(R.id.imageView2) + matchText(R.id.ph_expiry, data.phExpiry!!) + matchText(R.id.ph_no, data.phNumber!!) + } + } \ No newline at end of file diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/InsuranceRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/InsuranceRobot.kt index 348e066..54b6786 100644 --- a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/InsuranceRobot.kt +++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/InsuranceRobot.kt @@ -1,23 +1,24 @@ package h_mal.appttude.com.driver.robots.vehicle import h_mal.appttude.com.driver.FormRobot -import h_mal.appttude.com.driver.FormRobot.FilePath.Companion.getFilePath import h_mal.appttude.com.driver.R +import h_mal.appttude.com.driver.model.Insurance fun insurance(func: InsuranceRobot.() -> Unit) = InsuranceRobot().apply { func() } -class InsuranceRobot : FormRobot() { +class InsuranceRobot : FormRobot() { fun enterInsurance(text: String) = fillEditText(R.id.insurer, text) - fun enterInsuranceExpiry(year: Int, monthOfYear: Int, dayOfMonth: Int) = - setDate(R.id.insurance_exp, year, monthOfYear, dayOfMonth) + fun enterInsuranceExpiry(date: String) = setDate(R.id.insurance_exp, date) - fun selectImages() = - selectMultipleImage(R.id.uploadInsurance, arrayOf(getFilePath(FilePath.INSURANCE))) + override fun submitForm(data: Insurance) { + selectMultipleImage(R.id.uploadInsurance, data.photoStrings!!.map { it!! }) + enterInsurance(data.insurerName!!) + enterInsuranceExpiry(data.expiryDate!!) + super.submitForm(data) + } - fun submitForm(insurer: String, year: Int, monthOfYear: Int, dayOfMonth: Int) { - selectImages() - enterInsurance(insurer) - enterInsuranceExpiry(year, monthOfYear, dayOfMonth) - submit() + override fun validateSubmission(data: Insurance) { + matchText(R.id.insurer, data.insurerName!!) + matchText(R.id.insurance_exp, data.expiryDate!!) } } \ No newline at end of file diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/LogbookRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/LogbookRobot.kt index 33d69ad..ade64b0 100644 --- a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/LogbookRobot.kt +++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/LogbookRobot.kt @@ -2,17 +2,21 @@ package h_mal.appttude.com.driver.robots.vehicle import h_mal.appttude.com.driver.FormRobot import h_mal.appttude.com.driver.R +import h_mal.appttude.com.driver.model.Logbook fun logbook(func: LogbookRobot.() -> Unit) = LogbookRobot().apply { func() } -class LogbookRobot : FormRobot() { +class LogbookRobot : FormRobot() { - fun selectImages() = selectSingleImage(R.id.uploadmot, FilePath.MOT) - fun enterExpiryDate(year: Int, monthOfYear: Int, dayOfMonth: Int) = - setDate(R.id.mot_expiry, year, monthOfYear, dayOfMonth) + fun enterV5c(v5c: String) = fillEditText(R.id.v5c_no, v5c) - fun submitForm(year: Int, monthOfYear: Int, dayOfMonth: Int) { - selectImages() - enterExpiryDate(year, monthOfYear, dayOfMonth) - submit() + override fun submitForm(data: Logbook) { + selectSingleImage(R.id.upload_lb, data.photoString!!) + enterV5c(data.v5cnumber!!) + super.submitForm(data) + } + + override fun validateSubmission(data: Logbook) { + checkImageViewDoesNotHaveDefaultImage(R.id.log_book_img) + matchText(R.id.v5c_no, data.v5cnumber!!) } } \ No newline at end of file diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/MOTRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/MOTRobot.kt index c6e1456..9e7bea7 100644 --- a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/MOTRobot.kt +++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/MOTRobot.kt @@ -2,16 +2,21 @@ package h_mal.appttude.com.driver.robots.vehicle import h_mal.appttude.com.driver.FormRobot import h_mal.appttude.com.driver.R +import h_mal.appttude.com.driver.model.Mot fun mot(func: MOTRobot.() -> Unit) = MOTRobot().apply { func() } -class MOTRobot : FormRobot() { +class MOTRobot : FormRobot() { - fun enterV5cNumber(v5c: String) = fillEditText(R.id.mot_expiry, v5c) - fun selectImages() = selectSingleImage(R.id.mot_expiry, FilePath.LOGBOOK) + fun enterMotExpiry(expiry: String) = setDate(R.id.mot_expiry, expiry) - fun submitForm(v5c: String) { - selectImages() - enterV5cNumber(v5c) - submit() + override fun submitForm(data: Mot) { + selectSingleImage(R.id.uploadmot, data.motImageString!!) + enterMotExpiry(data.motExpiry!!) + super.submitForm(data) + } + + override fun validateSubmission(data: Mot) { + checkImageViewDoesNotHaveDefaultImage(R.id.mot_img) + matchText(R.id.mot_expiry, data.motExpiry!!) } } \ No newline at end of file diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/PrivateHireVehicleLicenseRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/PrivateHireVehicleLicenseRobot.kt index 4dd7a81..c7f5b18 100644 --- a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/PrivateHireVehicleLicenseRobot.kt +++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/PrivateHireVehicleLicenseRobot.kt @@ -2,22 +2,28 @@ package h_mal.appttude.com.driver.robots.vehicle import h_mal.appttude.com.driver.FormRobot import h_mal.appttude.com.driver.R +import h_mal.appttude.com.driver.model.PrivateHireVehicle fun privateHireVehicleLicense(func: PrivateHireVehicleLicenseRobot.() -> Unit) = PrivateHireVehicleLicenseRobot().apply { func() } - -class PrivateHireVehicleLicenseRobot : FormRobot() { +class PrivateHireVehicleLicenseRobot : FormRobot() { fun enterLicenseNumber(text: String) = fillEditText(R.id.ph_no, text) - fun enterLicenseExpiry(year: Int, monthOfYear: Int, dayOfMonth: Int) = - setDate(R.id.ph_expiry, year, monthOfYear, dayOfMonth) + fun enterLicenseExpiry(date: String) = setDate(R.id.ph_expiry, date) - fun selectImage() = selectSingleImage(R.id.uploadphlic, FilePath.PRIVATE_HIRE) + override fun submitForm(data: PrivateHireVehicle) { + selectSingleImage( + matchText(R.string.upload_private_hire_photo), + data.phCarImageString!! + ) + enterLicenseNumber(data.phCarNumber!!) + enterLicenseExpiry(data.phCarExpiry!!) + super.submitForm(data) + } - fun submitForm(licenseNumber: String, year: Int, monthOfYear: Int, dayOfMonth: Int) { - selectImage() - enterLicenseNumber(licenseNumber) - enterLicenseExpiry(year, monthOfYear, dayOfMonth) - submit() + override fun validateSubmission(data: PrivateHireVehicle) { + checkImageViewDoesNotHaveDefaultImage(R.id.imageView2) + matchText(R.id.ph_no, data.phCarNumber!!) + matchText(R.id.ph_expiry, data.phCarExpiry!!) } } \ No newline at end of file diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/VehicleProfileRobot.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/VehicleProfileRobot.kt index a168b4d..ef83c42 100644 --- a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/VehicleProfileRobot.kt +++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/robots/vehicle/VehicleProfileRobot.kt @@ -1,46 +1,51 @@ package h_mal.appttude.com.driver.robots.vehicle +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.isChecked +import androidx.test.espresso.matcher.ViewMatchers.isNotChecked import h_mal.appttude.com.driver.FormRobot import h_mal.appttude.com.driver.R import h_mal.appttude.com.driver.helpers.EspressoHelper.setChecked +import h_mal.appttude.com.driver.model.VehicleProfile fun vehicleProfile(func: VehicleProfileRobot.() -> Unit) = VehicleProfileRobot().apply { func() } -class VehicleProfileRobot : FormRobot() { - - fun enterRegistration(reg: String) = fillEditText(R.id.reg, reg) - fun enterMake(make: String) = fillEditText(R.id.make, make) - fun enterModel(model: String) = fillEditText(R.id.car_model, model) - fun enterColour(colour: String) = fillEditText(R.id.colour, colour) - fun enterAddress(address: String) = fillEditText(R.id.address, address) - fun enterPostcode(postCode: String) = fillEditText(R.id.postcode, postCode) - fun enterKeeperName(name: String) = fillEditText(R.id.keeper_name, name) - fun enterDateFirstAvailable(year: Int, monthOfYear: Int, dayOfMonth: Int) = - setDate(R.id.start_date, year, monthOfYear, dayOfMonth) +class VehicleProfileRobot : FormRobot() { + fun enterRegistration(reg: String) = scrollAndFillEditText(R.id.reg, reg) + fun enterMake(make: String) = scrollAndFillEditText(R.id.make, make) + fun enterModel(model: String) = scrollAndFillEditText(R.id.car_model, model) + fun enterColour(colour: String) = scrollAndFillEditText(R.id.colour, colour) + fun enterAddress(address: String) = scrollAndFillEditText(R.id.address, address) + fun enterPostcode(postCode: String) = scrollAndFillEditText(R.id.postcode, postCode) + fun enterKeeperName(name: String) = scrollAndFillEditText(R.id.keeper_name, name) + fun enterDateFirstAvailable(date: String) = scrollAndSetDate(R.id.start_date, date) fun isSeized(seized: Boolean) = matchView(R.id.seized_checkbox).perform(setChecked(seized)) - fun submitForm( - reg: String, - make: String, - model: String, - colour: String, - address: String, - postCode: String, - name: String, - year: Int, - monthOfYear: Int, - dayOfMonth: Int, - seized: Boolean = false - ) { - enterRegistration(reg) - enterMake(make) - enterModel(model) - enterColour(colour) - enterAddress(address) - enterPostcode(postCode) - enterKeeperName(name) - enterDateFirstAvailable(year, monthOfYear, dayOfMonth) - isSeized(seized) - submit() + + override fun submitForm(data: VehicleProfile) { + enterRegistration(data.reg!!) + enterMake(data.make!!) + enterModel(data.model!!) + enterColour(data.colour!!) + enterAddress(data.keeperAddress!!) + enterPostcode(data.keeperPostCode!!) + enterKeeperName(data.keeperName!!) + enterDateFirstAvailable(data.startDate!!) + isSeized(data.isSeized) + super.submitForm(data) + } + + override fun validateSubmission(data: VehicleProfile) { + matchText(R.id.reg, data.reg!!) + matchText(R.id.make, data.make!!) + matchText(R.id.car_model, data.model!!) + matchText(R.id.colour, data.colour!!) + matchText(R.id.address, data.keeperAddress!!) + matchText(R.id.postcode, data.keeperPostCode!!) + matchText(R.id.keeper_name, data.keeperName!!) + matchText(R.id.start_date, data.startDate!!) + val checking = if (data.isSeized) isChecked() else isNotChecked() + matchView(R.id.seized_checkbox).check(matches(checking)) + super.validateSubmission(data) } } \ No newline at end of file diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/DataSubmissionTest.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/DataSubmissionTest.kt new file mode 100644 index 0000000..d42ec68 --- /dev/null +++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/DataSubmissionTest.kt @@ -0,0 +1,52 @@ +package h_mal.appttude.com.driver.tests.newUser + +import androidx.test.espresso.matcher.ViewMatchers.withText +import h_mal.appttude.com.driver.FirebaseTest +import h_mal.appttude.com.driver.R +import h_mal.appttude.com.driver.helpers.EspressoHelper.trying +import h_mal.appttude.com.driver.helpers.EspressoHelper.waitForView +import h_mal.appttude.com.driver.model.DriverProfile +import h_mal.appttude.com.driver.model.DriversLicense +import h_mal.appttude.com.driver.model.Insurance +import h_mal.appttude.com.driver.model.Logbook +import h_mal.appttude.com.driver.model.Model +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 +import h_mal.appttude.com.driver.robots.home +import h_mal.appttude.com.driver.ui.MainActivity +import java.io.IOException + +open class DataSubmissionTest : + FirebaseTest(MainActivity::class.java, registered = true, signedIn = true) { + + + override fun afterLaunch() { + super.afterLaunch() + home { + waitForView(withText(getResourceString(R.string.welcome_title)), waitMillis = 10000) + trying { + requestProfile() + } + } + } + + inline fun getAssetData(): T { + val file = when (T::class) { + DriverProfile::class -> "driver_details" + DriversLicense::class -> "drivers_license" + Insurance::class -> "insurance_details" + Logbook::class -> "log_book" + Mot::class -> "mot_details" + PrivateHireLicense::class -> "private_hire_license" + PrivateHireVehicle::class -> "private_hire_vehicle" + VehicleProfile::class -> "vehicle_details" + else -> { + throw IOException("No file for ${T::class}") + } + } + return readDataFromAsset(file) + } + +} \ No newline at end of file diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/DriverProfileTest.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/DriverProfileTest.kt new file mode 100644 index 0000000..5ff1eb8 --- /dev/null +++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/DriverProfileTest.kt @@ -0,0 +1,13 @@ +package h_mal.appttude.com.driver.tests.newUser + +import h_mal.appttude.com.driver.robots.home + +open class DriverProfileTest : DataSubmissionTest() { + + override fun afterLaunch() { + super.afterLaunch() + home { + openDriverProfile() + } + } +} \ No newline at end of file diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/SubmitNewDataActivityTest.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/SubmitNewDataActivityTest.kt deleted file mode 100644 index 631a08c..0000000 --- a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/SubmitNewDataActivityTest.kt +++ /dev/null @@ -1,37 +0,0 @@ -package h_mal.appttude.com.driver.tests.newUser - - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.LargeTest -import androidx.test.rule.GrantPermissionRule -import h_mal.appttude.com.driver.FirebaseTest -import h_mal.appttude.com.driver.R -import h_mal.appttude.com.driver.robots.* -import h_mal.appttude.com.driver.robots.driver.driversLicense -import h_mal.appttude.com.driver.ui.MainActivity -import org.junit.* -import org.junit.runner.RunWith - - -@LargeTest -@RunWith(AndroidJUnit4::class) -class SubmitNewDataActivityTest : - FirebaseTest(MainActivity::class.java, registered = true, signedIn = true) { - - @Test - fun verifyUserRegistration_validUsernameAndPassword_loggedIn() { - home { - waitFor(2500) - checkTitleExists(getResourceString(R.string.welcome_title)) - requestProfile() - openDriverProfile() - } - driverScreen { - driverLicense() - } - driversLicense { - submitForm("SAMPLE8456310LTU", 2022, 10, 2) - } - } - -} diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/SubmitNewDriverDataTest.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/SubmitNewDriverDataTest.kt new file mode 100644 index 0000000..bde80c5 --- /dev/null +++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/SubmitNewDriverDataTest.kt @@ -0,0 +1,54 @@ +package h_mal.appttude.com.driver.tests.newUser + + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.LargeTest +import h_mal.appttude.com.driver.model.DriverProfile +import h_mal.appttude.com.driver.model.DriversLicense +import h_mal.appttude.com.driver.model.PrivateHireLicense +import h_mal.appttude.com.driver.robots.* +import h_mal.appttude.com.driver.robots.driver.driversLicense +import h_mal.appttude.com.driver.robots.driver.driversProfile +import h_mal.appttude.com.driver.robots.driver.privateHireLicenseRobot +import org.junit.* +import org.junit.runner.RunWith + + +@LargeTest +@RunWith(AndroidJUnit4::class) +class SubmitNewDriverDataTest : DriverProfileTest() { + + @Test + fun signedInUser_uploadsValidLicenseDetails_uploadSuccessful() { + driverScreen { + driverLicense() + } + driversLicense { + val data = getAssetData() + submitAndValidate(data) + } + } + + @Test + fun signedInUser_uploadsValidDriverDetails_uploadSuccessful() { + driverScreen { + driverProfile() + } + driversProfile { + val data = getAssetData() + submitAndValidate(data) + } + } + + @Test + fun signedInUser_uploadsValidPrivateHireDetails_uploadSuccessful() { + driverScreen { + privateHireLicense() + } + privateHireLicenseRobot { + val data = getAssetData() + submitAndValidate(data) + } + } + +} diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/SubmitNewVehicleDataTest.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/SubmitNewVehicleDataTest.kt new file mode 100644 index 0000000..a568dc0 --- /dev/null +++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/SubmitNewVehicleDataTest.kt @@ -0,0 +1,80 @@ +package h_mal.appttude.com.driver.tests.newUser + + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.LargeTest +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.PrivateHireVehicle +import h_mal.appttude.com.driver.model.VehicleProfile +import h_mal.appttude.com.driver.robots.* +import h_mal.appttude.com.driver.robots.vehicle.insurance +import h_mal.appttude.com.driver.robots.vehicle.logbook +import h_mal.appttude.com.driver.robots.vehicle.mot +import h_mal.appttude.com.driver.robots.vehicle.privateHireVehicleLicense +import h_mal.appttude.com.driver.robots.vehicle.vehicleProfile +import org.junit.* +import org.junit.runner.RunWith + + +@LargeTest +@RunWith(AndroidJUnit4::class) +class SubmitNewVehicleDataTest : VehicleProfileTest() { + + @Test + fun signedInUser_uploadsValidVehicleProfile_uploadSuccessful() { + vehicleScreen { + vehicleProfile() + } + vehicleProfile { + val data = getAssetData() + submitAndValidate(data) + } + } + + @Test + fun signedInUser_uploadsValidInsurance_uploadSuccessful() { + vehicleScreen { + insurance() + } + insurance { + val data = getAssetData() + submitAndValidate(data) + } + } + + @Test + fun signedInUser_uploadsValidMot_uploadSuccessful() { + vehicleScreen { + mot() + } + mot { + val data = getAssetData() + submitAndValidate(data) + } + } + + @Test + fun signedInUser_uploadsValidLogbook_uploadSuccessful() { + vehicleScreen { + logbook() + } + logbook { + val data = getAssetData() + submitAndValidate(data) + } + } + + @Test + fun signedInUser_uploadsValidPrivateHireVehicleLicense_uploadSuccessful() { + vehicleScreen { + privateHireVehicleLicense() + } + privateHireVehicleLicense { + val data = getAssetData() + submitAndValidate(data) + } + } + +} diff --git a/app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/VehicleProfileTest.kt b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/VehicleProfileTest.kt new file mode 100644 index 0000000..384fcf5 --- /dev/null +++ b/app/src/androidTestDriver/java/h_mal/appttude/com/driver/tests/newUser/VehicleProfileTest.kt @@ -0,0 +1,13 @@ +package h_mal.appttude.com.driver.tests.newUser + +import h_mal.appttude.com.driver.robots.home + +open class VehicleProfileTest : DataSubmissionTest() { + + override fun afterLaunch() { + super.afterLaunch() + home { + openVehicleProfile() + } + } +} \ No newline at end of file diff --git a/app/src/driver/java/h_mal/appttude/com/driver/application/ApplicationViewModelFactory.kt b/app/src/driver/java/h_mal/appttude/com/driver/application/ApplicationViewModelFactory.kt index 0f81ab1..53458fb 100644 --- a/app/src/driver/java/h_mal/appttude/com/driver/application/ApplicationViewModelFactory.kt +++ b/app/src/driver/java/h_mal/appttude/com/driver/application/ApplicationViewModelFactory.kt @@ -5,7 +5,6 @@ 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( diff --git a/app/src/driver/java/h_mal/appttude/com/driver/application/DriverApplication.kt b/app/src/driver/java/h_mal/appttude/com/driver/application/DriverApplication.kt index 855d97a..89f2a5c 100644 --- a/app/src/driver/java/h_mal/appttude/com/driver/application/DriverApplication.kt +++ b/app/src/driver/java/h_mal/appttude/com/driver/application/DriverApplication.kt @@ -1,18 +1,8 @@ package h_mal.appttude.com.driver.application -import android.app.Application -import android.content.res.Resources -import h_mal.appttude.com.driver.data.FirebaseAuthSource -import h_mal.appttude.com.driver.data.FirebaseDatabaseSource -import h_mal.appttude.com.driver.data.FirebaseStorageSource -import h_mal.appttude.com.driver.data.prefs.PreferenceProvider -import org.kodein.di.Kodein -import org.kodein.di.KodeinAware -import org.kodein.di.android.x.androidXModule import org.kodein.di.generic.bind import org.kodein.di.generic.instance import org.kodein.di.generic.provider -import org.kodein.di.generic.singleton class DriverApplication : BaseApplication() { diff --git a/app/src/driver/java/h_mal/appttude/com/driver/ui/HomeFragment.kt b/app/src/driver/java/h_mal/appttude/com/driver/ui/HomeFragment.kt index 2aadb99..cbccc2f 100644 --- a/app/src/driver/java/h_mal/appttude/com/driver/ui/HomeFragment.kt +++ b/app/src/driver/java/h_mal/appttude/com/driver/ui/HomeFragment.kt @@ -3,7 +3,7 @@ package h_mal.appttude.com.driver.ui import android.os.Bundle import android.view.View import h_mal.appttude.com.driver.R -import h_mal.appttude.com.driver.base.DataSubmissionBaseFragment +import h_mal.appttude.com.driver.base.BaseFragment import h_mal.appttude.com.driver.data.DRIVER import h_mal.appttude.com.driver.databinding.FragmentHomeDriverBinding import h_mal.appttude.com.driver.utils.hide @@ -13,9 +13,7 @@ import h_mal.appttude.com.driver.viewmodels.RoleViewModel class HomeFragment : - DataSubmissionBaseFragment() { - - override var model = String() + BaseFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/app/src/driver/java/h_mal/appttude/com/driver/ui/driverprofile/DriverLicenseFragment.kt b/app/src/driver/java/h_mal/appttude/com/driver/ui/driverprofile/DriverLicenseFragment.kt index ffddae4..daaeed2 100644 --- a/app/src/driver/java/h_mal/appttude/com/driver/ui/driverprofile/DriverLicenseFragment.kt +++ b/app/src/driver/java/h_mal/appttude/com/driver/ui/driverprofile/DriverLicenseFragment.kt @@ -12,8 +12,6 @@ import h_mal.appttude.com.driver.viewmodels.DriverLicenseViewModel class DriverLicenseFragment : DataSubmissionBaseFragment() { - override var model = DriversLicense() - override fun setupView(binding: FragmentDriverLicenseBinding) { binding.apply { licExpiry.apply { diff --git a/app/src/driver/java/h_mal/appttude/com/driver/ui/driverprofile/DriverProfileFragment.kt b/app/src/driver/java/h_mal/appttude/com/driver/ui/driverprofile/DriverProfileFragment.kt index 9bf7614..ec861a2 100644 --- a/app/src/driver/java/h_mal/appttude/com/driver/ui/driverprofile/DriverProfileFragment.kt +++ b/app/src/driver/java/h_mal/appttude/com/driver/ui/driverprofile/DriverProfileFragment.kt @@ -1,8 +1,8 @@ package h_mal.appttude.com.driver.ui.driverprofile import android.net.Uri -import h_mal.appttude.com.driver.databinding.FragmentDriverProfileBinding import h_mal.appttude.com.driver.base.DataSubmissionBaseFragment +import h_mal.appttude.com.driver.databinding.FragmentDriverProfileBinding import h_mal.appttude.com.driver.dialogs.DateDialog import h_mal.appttude.com.driver.model.DriverProfile import h_mal.appttude.com.driver.utils.isTrue @@ -13,8 +13,6 @@ import h_mal.appttude.com.driver.viewmodels.DriverProfileViewModel class DriverProfileFragment : DataSubmissionBaseFragment() { - override var model = DriverProfile() - override fun setupView(binding: FragmentDriverProfileBinding) = binding.run { namesInput.setTextOnChange { model.forenames = it } addressInput.setTextOnChange { model.address = it } diff --git a/app/src/driver/java/h_mal/appttude/com/driver/ui/driverprofile/PrivateHireLicenseFragment.kt b/app/src/driver/java/h_mal/appttude/com/driver/ui/driverprofile/PrivateHireLicenseFragment.kt index 8c92dbd..a8ca6dc 100644 --- a/app/src/driver/java/h_mal/appttude/com/driver/ui/driverprofile/PrivateHireLicenseFragment.kt +++ b/app/src/driver/java/h_mal/appttude/com/driver/ui/driverprofile/PrivateHireLicenseFragment.kt @@ -13,8 +13,6 @@ import h_mal.appttude.com.driver.viewmodels.PrivateHireLicenseViewModel class PrivateHireLicenseFragment : DataSubmissionBaseFragment () { - override var model = PrivateHireLicense() - override fun setupView(binding: FragmentPrivateHireLicenseBinding) = binding.run { phNo.setTextOnChange { model.phNumber = it } phExpiry.apply { diff --git a/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/InsuranceFragment.kt b/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/InsuranceFragment.kt index 535fd10..a1fe911 100644 --- a/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/InsuranceFragment.kt +++ b/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/InsuranceFragment.kt @@ -18,8 +18,6 @@ class InsuranceFragment : private var selectedImages: List? = listOf() - override var model = Insurance() - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setImageSelectionAsMultiple() diff --git a/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/LogbookFragment.kt b/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/LogbookFragment.kt index be5afe7..6970fc6 100644 --- a/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/LogbookFragment.kt +++ b/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/LogbookFragment.kt @@ -12,8 +12,6 @@ import h_mal.appttude.com.driver.viewmodels.LogbookViewModel class LogbookFragment : DataSubmissionBaseFragment() { - override var model = Logbook() - override fun setupView(binding: FragmentLogbookBinding) = binding.run { v5cNo.setTextOnChange { model.v5cnumber = it } uploadLb.setOnClickListener { openGalleryWithPermissionRequest() } diff --git a/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/MotFragment.kt b/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/MotFragment.kt index f129729..10b5afa 100644 --- a/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/MotFragment.kt +++ b/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/MotFragment.kt @@ -12,8 +12,6 @@ import h_mal.appttude.com.driver.viewmodels.MotViewModel class MotFragment : DataSubmissionBaseFragment() { - override var model = Mot() - override fun setupView(binding: FragmentMotBinding) = binding.run { motExpiry.apply { setOnClickListener { diff --git a/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/PrivateHireVehicleFragment.kt b/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/PrivateHireVehicleFragment.kt index aaa8ab8..1bcada4 100644 --- a/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/PrivateHireVehicleFragment.kt +++ b/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/PrivateHireVehicleFragment.kt @@ -13,8 +13,6 @@ import h_mal.appttude.com.driver.viewmodels.PrivateHireVehicleViewModel class PrivateHireVehicleFragment : DataSubmissionBaseFragment() { - override var model = PrivateHireVehicle() - override fun setupView(binding: FragmentPrivateHireLicenseBinding) = binding.run { phNo.setTextOnChange { model.phCarNumber = it } phExpiry.apply { diff --git a/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/VehicleProfileFragment.kt b/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/VehicleProfileFragment.kt index 650c70c..17c91c2 100644 --- a/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/VehicleProfileFragment.kt +++ b/app/src/driver/java/h_mal/appttude/com/driver/ui/vehicleprofile/VehicleProfileFragment.kt @@ -11,8 +11,6 @@ import h_mal.appttude.com.driver.viewmodels.VehicleProfileViewModel class VehicleProfileFragment : DataSubmissionBaseFragment () { - override var model = VehicleProfile() - override fun setupView(binding: FragmentVehicleSetupBinding) = binding.run { reg.setTextOnChange { model.reg = it } make.setTextOnChange { model.make = it } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9c321a0..6169748 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,8 +14,8 @@ android:theme="@style/AppTheme"> + android:exported="true" + android:theme="@style/AppTheme.NoActionBar.User"> diff --git a/app/src/main/java/h_mal/appttude/com/driver/application/BaseApplication.kt b/app/src/main/java/h_mal/appttude/com/driver/application/BaseApplication.kt index 78a4740..78f878e 100644 --- a/app/src/main/java/h_mal/appttude/com/driver/application/BaseApplication.kt +++ b/app/src/main/java/h_mal/appttude/com/driver/application/BaseApplication.kt @@ -1,17 +1,25 @@ package h_mal.appttude.com.driver.application import android.app.Application +import androidx.startup.AppInitializer 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 net.danlew.android.joda.JodaTimeInitializer import org.kodein.di.Kodein import org.kodein.di.KodeinAware import org.kodein.di.android.x.androidXModule import org.kodein.di.generic.bind import org.kodein.di.generic.singleton +const val GLOBAL_FORMAT = "dd/MM/yyyy" open class BaseApplication : Application(), KodeinAware { + override fun onCreate() { + super.onCreate() + AppInitializer.getInstance(this).initializeComponent(JodaTimeInitializer::class.java) + } + // Kodein aware to initialise the classes used for DI override val kodein = Kodein.lazy { import(parentModule) diff --git a/app/src/main/java/h_mal/appttude/com/driver/base/BaseActivity.kt b/app/src/main/java/h_mal/appttude/com/driver/base/BaseActivity.kt index c20577e..51bc1a4 100644 --- a/app/src/main/java/h_mal/appttude/com/driver/base/BaseActivity.kt +++ b/app/src/main/java/h_mal/appttude/com/driver/base/BaseActivity.kt @@ -4,7 +4,6 @@ import android.content.Intent import android.os.Build import android.os.Bundle import android.view.View -import android.view.View.OnAttachStateChangeListener import android.view.ViewGroup.LayoutParams import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.view.ViewGroup.inflate @@ -156,15 +155,18 @@ abstract class BaseActivity : AppCompatActi super.onToastHidden() mIdlingResource?.setIdleState(true) } + override fun onToastShown() { super.onToastShown() mIdlingResource?.setIdleState(false) } }) + toast.show() } else { - + mIdlingResource?.setIdleState(true) + toast.show() + mIdlingResource?.setIdleState(false) } - toast.show() } fun showSnackBar(message: String) { @@ -178,6 +180,7 @@ abstract class BaseActivity : AppCompatActi super.onShown(transientBottomBar) mIdlingResource?.setIdleState(false) } + override fun onDismissed(transientBottomBar: Snackbar?, event: Int) { super.onDismissed(transientBottomBar, event) mIdlingResource?.setIdleState(true) diff --git a/app/src/main/java/h_mal/appttude/com/driver/base/BaseFirebaseAdapter.kt b/app/src/main/java/h_mal/appttude/com/driver/base/BaseFirebaseAdapter.kt index 62b13c5..d8863b8 100644 --- a/app/src/main/java/h_mal/appttude/com/driver/base/BaseFirebaseAdapter.kt +++ b/app/src/main/java/h_mal/appttude/com/driver/base/BaseFirebaseAdapter.kt @@ -59,6 +59,7 @@ open class BaseFirebaseAdapter( super.onDataChanged() if (itemCount == 0) emptyList() } + override fun onError(error: DatabaseError) { super.onError(error) when (error.code) { diff --git a/app/src/main/java/h_mal/appttude/com/driver/base/BaseFragment.kt b/app/src/main/java/h_mal/appttude/com/driver/base/BaseFragment.kt index e80b26e..afb8fbe 100644 --- a/app/src/main/java/h_mal/appttude/com/driver/base/BaseFragment.kt +++ b/app/src/main/java/h_mal/appttude/com/driver/base/BaseFragment.kt @@ -1,14 +1,9 @@ package h_mal.appttude.com.driver.base -import android.content.ClipData -import android.content.Context -import android.content.Intent -import android.net.Uri import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.activity.result.contract.ActivityResultContract import androidx.fragment.app.Fragment import androidx.fragment.app.createViewModelLazy import androidx.viewbinding.ViewBinding @@ -16,7 +11,6 @@ import h_mal.appttude.com.driver.application.ApplicationViewModelFactory import h_mal.appttude.com.driver.data.ViewState import h_mal.appttude.com.driver.utils.GenericsHelper.getGenericClassAt import h_mal.appttude.com.driver.utils.GenericsHelper.inflateBindingByType -import h_mal.appttude.com.driver.utils.PermissionsUtils import org.kodein.di.KodeinAware import org.kodein.di.android.x.kodein import org.kodein.di.generic.instance @@ -36,12 +30,6 @@ abstract class BaseFragment : Fragment(), K private fun getFragmentViewModel(): Lazy = createViewModelLazy(getGenericClassAt(0), { viewModelStore }, factoryProducer = { factory }) - private var multipleImage: Boolean = false - - fun setImageSelectionAsMultiple() { - multipleImage = true - } - override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -101,73 +89,6 @@ abstract class BaseFragment : Fragment(), K } } - private fun ClipData.convertToList(): List = 0.rangeTo(itemCount).map { getItemAt(it).uri } - - /** - * Pair with {@link #Fragment.onRequestPermissionsResult} - * @param ourRequestCode - * @param requestCode - * checks that ourRequestCode was granted - * sends callback with - * @param permissionGranted - */ - fun onPermissionRequest( - requestCode: Int, ourRequestCode: Int, grantResults: IntArray, - permissionGranted: () -> Unit - ) { - when (requestCode) { - ourRequestCode -> { - if (PermissionsUtils.isGranted(grantResults)) { - permissionGranted.invoke() - } - return - } - } - } - - /** - * Called on the result of image selection - */ - open fun onImageGalleryResult(imageUri: Uri?) {} - - /** - * Called on the result of multiple image selection - */ - open fun onImageGalleryResult(imageUris: List?) {} - - fun openGalleryForImage() { - permissionRequest.launch(multipleImage) - } - - private val permissionRequest = registerForActivityResult(getResultsContract()) { result -> - @Suppress("UNCHECKED_CAST") - when (result) { - is Uri -> onImageGalleryResult(result) - is List<*> -> onImageGalleryResult(result as List) - } - } - - private fun getResultsContract(): ActivityResultContract { - return object : ActivityResultContract() { - override fun createIntent(context: Context, input: Boolean): Intent { - return Intent(Intent.ACTION_GET_CONTENT) - .addCategory(Intent.CATEGORY_OPENABLE) - .putExtra(Intent.EXTRA_ALLOW_MULTIPLE, input) - .setType("image/*") - } - - override fun parseResult(resultCode: Int, intent: Intent?): Any? { - intent?.clipData?.takeIf { it.itemCount > 1 }?.convertToList()?.let { clip -> - val list = clip.takeIf { it.size > 10 }?.let { - clip.subList(0, 9) - } ?: clip - return list - } - return intent?.data - } - } - } - fun showToast(message: String) = (activity as BaseActivity<*, *>).showToast(message) fun showSnackBar(message: String) = (activity as BaseActivity<*, *>).showSnackBar(message) } \ No newline at end of file diff --git a/app/src/main/java/h_mal/appttude/com/driver/base/DataSubmissionBaseFragment.kt b/app/src/main/java/h_mal/appttude/com/driver/base/DataSubmissionBaseFragment.kt index 5f18b90..0823d55 100644 --- a/app/src/main/java/h_mal/appttude/com/driver/base/DataSubmissionBaseFragment.kt +++ b/app/src/main/java/h_mal/appttude/com/driver/base/DataSubmissionBaseFragment.kt @@ -1,26 +1,22 @@ package h_mal.appttude.com.driver.base -import android.Manifest import android.content.Intent -import android.net.Uri import android.os.Bundle import android.view.View import android.widget.EditText import androidx.core.widget.doAfterTextChanged import androidx.viewbinding.ViewBinding import h_mal.appttude.com.driver.data.UserAuthState +import h_mal.appttude.com.driver.model.Model import h_mal.appttude.com.driver.ui.user.LoginActivity -import h_mal.appttude.com.driver.utils.PermissionsUtils.askForPermissions +import h_mal.appttude.com.driver.utils.GenericsHelper.getGenericClassAt import h_mal.appttude.com.driver.utils.TextValidationUtils.validateEditText +import kotlin.reflect.full.createInstance -private const val IMAGE_PERMISSION_RESULT = 402 +abstract class DataSubmissionBaseFragment, VB : ViewBinding, T : Model> : + ImageSelectorFragment() { -abstract class DataSubmissionBaseFragment, VB : ViewBinding, T : Any> : - BaseFragment() { - - var picUri: Uri? = null - - abstract var model: T + var model: T = getGenericClassAt(2).createInstance() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -52,17 +48,7 @@ abstract class DataSubmissionBaseFragment, VB open fun submit() {} fun openGalleryWithPermissionRequest() { - if (askForPermissions(Manifest.permission.READ_EXTERNAL_STORAGE, IMAGE_PERMISSION_RESULT)) { - openGalleryForImage() - } - } - - override fun onRequestPermissionsResult( - requestCode: Int, - permissions: Array, - grantResults: IntArray - ) = onPermissionRequest(requestCode, IMAGE_PERMISSION_RESULT, grantResults) { - openGalleryForImage() + showStorageWithPermissionCheck() } fun validateEditTexts(vararg editTexts: EditText): Boolean { @@ -81,8 +67,4 @@ abstract class DataSubmissionBaseFragment, VB } } - override fun onImageGalleryResult(imageUri: Uri?) { - super.onImageGalleryResult(imageUri) - picUri = imageUri - } } \ No newline at end of file diff --git a/app/src/main/java/h_mal/appttude/com/driver/base/DrawerActivity.kt b/app/src/main/java/h_mal/appttude/com/driver/base/DrawerActivity.kt index 22194a2..563a64f 100644 --- a/app/src/main/java/h_mal/appttude/com/driver/base/DrawerActivity.kt +++ b/app/src/main/java/h_mal/appttude/com/driver/base/DrawerActivity.kt @@ -25,7 +25,7 @@ abstract class DrawerActivity : BaseActivit abstract val containerId: Int abstract val drawerLayoutId: Int abstract val toolbarId: Int - abstract val navViewId:Int + abstract val navViewId: Int lateinit var navController: NavController lateinit var appBarConfiguration: AppBarConfiguration diff --git a/app/src/main/java/h_mal/appttude/com/driver/base/ImageSelectorFragment.kt b/app/src/main/java/h_mal/appttude/com/driver/base/ImageSelectorFragment.kt new file mode 100644 index 0000000..a5ee6b0 --- /dev/null +++ b/app/src/main/java/h_mal/appttude/com/driver/base/ImageSelectorFragment.kt @@ -0,0 +1,107 @@ +package h_mal.appttude.com.driver.base + +import android.Manifest +import android.content.ClipData +import android.content.Context +import android.content.Intent +import android.net.Uri +import androidx.activity.result.contract.ActivityResultContract +import androidx.viewbinding.ViewBinding +import h_mal.appttude.com.driver.ui.permission.PermissionsDeclarationDialog +import permissions.dispatcher.NeedsPermission +import permissions.dispatcher.OnNeverAskAgain +import permissions.dispatcher.OnPermissionDenied +import permissions.dispatcher.OnShowRationale +import permissions.dispatcher.PermissionRequest +import permissions.dispatcher.RuntimePermissions + +@RuntimePermissions +open class ImageSelectorFragment : BaseFragment() { + private var multipleImage: Boolean = false + var picUri: Uri? = null + + fun setImageSelectionAsMultiple() { + multipleImage = true + } + + fun openGalleryForImage() { + permissionRequest.launch(multipleImage) + } + + private val permissionRequest = registerForActivityResult(getResultsContract()) { result -> + @Suppress("UNCHECKED_CAST") + when (result) { + is Uri -> onImageGalleryResult(result) + is List<*> -> onImageGalleryResult(result as List) + } + } + + private fun getResultsContract(): ActivityResultContract { + return object : ActivityResultContract() { + override fun createIntent(context: Context, input: Boolean): Intent { + return Intent(Intent.ACTION_GET_CONTENT) + .addCategory(Intent.CATEGORY_OPENABLE) + .putExtra(Intent.EXTRA_ALLOW_MULTIPLE, input) + .setType("image/*") + } + + override fun parseResult(resultCode: Int, intent: Intent?): Any? { + intent?.clipData?.takeIf { it.itemCount > 1 }?.convertToList()?.let { clip -> + val list = clip.takeIf { it.size > 10 }?.let { + clip.subList(0, 9) + } ?: clip + return list + } + return intent?.data + } + } + } + + private fun ClipData.convertToList(): List = 0.rangeTo(itemCount).map { getItemAt(it).uri } + + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + // NOTE: delegate the permission handling to generated method + onRequestPermissionsResult(requestCode, grantResults) + } + + @NeedsPermission(Manifest.permission.READ_EXTERNAL_STORAGE) + fun showStorage() { + openGalleryForImage() + } + + @OnShowRationale(Manifest.permission.READ_EXTERNAL_STORAGE) + fun showRationaleForStorage(request: PermissionRequest) { + PermissionsDeclarationDialog(requireContext()).showDialog({ + request.proceed() + }, { + request.cancel() + }) + } + + @OnPermissionDenied(Manifest.permission.READ_EXTERNAL_STORAGE) + fun onStorageDenied() { + showToast("Storage permissions have been denied") + } + + @OnNeverAskAgain(Manifest.permission.READ_EXTERNAL_STORAGE) + fun onStorageNeverAskAgain() { + showToast("Storage permissions have been to never ask again") + } + + /** + * Called on the result of image selection + */ + open fun onImageGalleryResult(imageUri: Uri?) { + picUri = imageUri + } + + /** + * Called on the result of multiple image selection + */ + open fun onImageGalleryResult(imageUris: List?) {} +} \ No newline at end of file diff --git a/app/src/main/java/h_mal/appttude/com/driver/data/prefs/PreferencesProvider.kt b/app/src/main/java/h_mal/appttude/com/driver/data/prefs/PreferencesProvider.kt index b017b28..7a990bd 100644 --- a/app/src/main/java/h_mal/appttude/com/driver/data/prefs/PreferencesProvider.kt +++ b/app/src/main/java/h_mal/appttude/com/driver/data/prefs/PreferencesProvider.kt @@ -10,7 +10,8 @@ import androidx.preference.PreferenceManager * */ const val SORT_OPTION = "SORT_OPTION" -class PreferenceProvider (context: Context) { + +class PreferenceProvider(context: Context) { private val appContext = context.applicationContext diff --git a/app/src/main/java/h_mal/appttude/com/driver/dialogs/DateDialog.kt b/app/src/main/java/h_mal/appttude/com/driver/dialogs/DateDialog.kt index 19d195a..345a0dc 100644 --- a/app/src/main/java/h_mal/appttude/com/driver/dialogs/DateDialog.kt +++ b/app/src/main/java/h_mal/appttude/com/driver/dialogs/DateDialog.kt @@ -3,14 +3,11 @@ package h_mal.appttude.com.driver.dialogs import android.app.DatePickerDialog import android.app.DatePickerDialog.OnDateSetListener -import android.icu.util.Calendar import android.widget.EditText import h_mal.appttude.com.driver.R import h_mal.appttude.com.driver.utils.DateUtils -private const val DATE_FORMAT = "dd/MM/yyyy" - @Suppress("DEPRECATION") class DateDialog( private val editText: EditText, @@ -19,10 +16,7 @@ class DateDialog( private val dateSetListener: OnDateSetListener = OnDateSetListener { _, year, month, dayOfMonth -> - val cal = Calendar.getInstance() - cal.set(year, month + 1, dayOfMonth) - - val date = DateUtils.parseCalenderIntoDateString(cal, DATE_FORMAT) + val date = DateUtils.getDateString(year, month, dayOfMonth) dateSelected(date) editText.setText(date) editText.error = null @@ -33,27 +27,17 @@ class DateDialog( spinnersShown = true calendarViewShown = false } - val dateString = editText.text?.toString() - val date = if (dateString.isNullOrBlank()) { - // Set time to now - Calendar.getInstance() - } else { - // Parse current edit text string and set value - DateUtils.parseDateStringIntoCalender(dateString, DATE_FORMAT) - ?: Calendar.getInstance() - } + val dateString = editText.text.toString() + val date = DateUtils.parseDateStringIntoCalender(dateString) + setDateFromCalender(date) setOnDateSetListener(dateSetListener) setTitle(context.getString(R.string.set_date)) show() } - private fun setDateFromCalender(calendar: Calendar) { - val mYear = calendar.get(Calendar.YEAR) - val mMonth = calendar.get(Calendar.MONTH) - val mDay = calendar.get(Calendar.DAY_OF_MONTH) - - updateDate(mYear, mMonth, mDay) + private fun setDateFromCalender(calendar: org.joda.time.LocalDate) { + updateDate(calendar.year, calendar.monthOfYear, calendar.dayOfMonth) } } \ No newline at end of file diff --git a/app/src/main/java/h_mal/appttude/com/driver/model/DriverProfile.kt b/app/src/main/java/h_mal/appttude/com/driver/model/DriverProfile.kt index eceddf3..f6f9fc8 100644 --- a/app/src/main/java/h_mal/appttude/com/driver/model/DriverProfile.kt +++ b/app/src/main/java/h_mal/appttude/com/driver/model/DriverProfile.kt @@ -8,4 +8,4 @@ data class DriverProfile( var dob: String? = null, var ni: String? = null, var dateFirst: String? = null -) \ No newline at end of file +) : Model \ No newline at end of file diff --git a/app/src/main/java/h_mal/appttude/com/driver/model/DriversLicense.kt b/app/src/main/java/h_mal/appttude/com/driver/model/DriversLicense.kt index bbebc73..fd34f65 100644 --- a/app/src/main/java/h_mal/appttude/com/driver/model/DriversLicense.kt +++ b/app/src/main/java/h_mal/appttude/com/driver/model/DriversLicense.kt @@ -5,4 +5,4 @@ data class DriversLicense( var licenseImageString: String? = null, var licenseNumber: String? = null, var licenseExpiry: String? = null -) \ No newline at end of file +) : Model \ No newline at end of file diff --git a/app/src/main/java/h_mal/appttude/com/driver/model/Insurance.kt b/app/src/main/java/h_mal/appttude/com/driver/model/Insurance.kt index 117f69d..07461e4 100644 --- a/app/src/main/java/h_mal/appttude/com/driver/model/Insurance.kt +++ b/app/src/main/java/h_mal/appttude/com/driver/model/Insurance.kt @@ -4,4 +4,4 @@ data class Insurance( var photoStrings: MutableList? = null, var insurerName: String? = null, var expiryDate: String? = null -) \ No newline at end of file +) : Model \ No newline at end of file diff --git a/app/src/main/java/h_mal/appttude/com/driver/model/Logbook.kt b/app/src/main/java/h_mal/appttude/com/driver/model/Logbook.kt index 783404d..ea74f49 100644 --- a/app/src/main/java/h_mal/appttude/com/driver/model/Logbook.kt +++ b/app/src/main/java/h_mal/appttude/com/driver/model/Logbook.kt @@ -4,4 +4,4 @@ package h_mal.appttude.com.driver.model data class Logbook( var photoString: String? = null, var v5cnumber: String? = null -) +) : Model diff --git a/app/src/main/java/h_mal/appttude/com/driver/model/Model.kt b/app/src/main/java/h_mal/appttude/com/driver/model/Model.kt new file mode 100644 index 0000000..004e1bc --- /dev/null +++ b/app/src/main/java/h_mal/appttude/com/driver/model/Model.kt @@ -0,0 +1,3 @@ +package h_mal.appttude.com.driver.model + +interface Model \ No newline at end of file diff --git a/app/src/main/java/h_mal/appttude/com/driver/model/Mot.kt b/app/src/main/java/h_mal/appttude/com/driver/model/Mot.kt index 4972e3c..10fa777 100644 --- a/app/src/main/java/h_mal/appttude/com/driver/model/Mot.kt +++ b/app/src/main/java/h_mal/appttude/com/driver/model/Mot.kt @@ -4,4 +4,4 @@ package h_mal.appttude.com.driver.model data class Mot( var motImageString: String? = null, var motExpiry: String? = null -) \ No newline at end of file +) : Model \ No newline at end of file diff --git a/app/src/main/java/h_mal/appttude/com/driver/model/PrivateHireLicense.kt b/app/src/main/java/h_mal/appttude/com/driver/model/PrivateHireLicense.kt index 9500840..9148c92 100644 --- a/app/src/main/java/h_mal/appttude/com/driver/model/PrivateHireLicense.kt +++ b/app/src/main/java/h_mal/appttude/com/driver/model/PrivateHireLicense.kt @@ -5,4 +5,4 @@ data class PrivateHireLicense( var phImageString: String? = null, var phNumber: String? = null, var phExpiry: String? = null -) \ No newline at end of file +) : Model \ No newline at end of file diff --git a/app/src/main/java/h_mal/appttude/com/driver/model/PrivateHireVehicle.kt b/app/src/main/java/h_mal/appttude/com/driver/model/PrivateHireVehicle.kt index 708087a..005a45a 100644 --- a/app/src/main/java/h_mal/appttude/com/driver/model/PrivateHireVehicle.kt +++ b/app/src/main/java/h_mal/appttude/com/driver/model/PrivateHireVehicle.kt @@ -1,8 +1,8 @@ package h_mal.appttude.com.driver.model -class PrivateHireVehicle( +data class PrivateHireVehicle( var phCarImageString: String? = null, var phCarNumber: String? = null, var phCarExpiry: String? = null -) \ No newline at end of file +) : Model \ No newline at end of file diff --git a/app/src/main/java/h_mal/appttude/com/driver/model/VehicleProfile.kt b/app/src/main/java/h_mal/appttude/com/driver/model/VehicleProfile.kt index 59ec3c0..106e68f 100644 --- a/app/src/main/java/h_mal/appttude/com/driver/model/VehicleProfile.kt +++ b/app/src/main/java/h_mal/appttude/com/driver/model/VehicleProfile.kt @@ -11,4 +11,4 @@ data class VehicleProfile( var keeperPostCode: String? = null, var startDate: String? = null, var isSeized: Boolean = false -) \ No newline at end of file +) : Model \ No newline at end of file diff --git a/app/src/main/java/h_mal/appttude/com/driver/ui/.idea/.gitignore b/app/src/main/java/h_mal/appttude/com/driver/ui/.idea/.gitignore deleted file mode 100644 index 26d3352..0000000 --- a/app/src/main/java/h_mal/appttude/com/driver/ui/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/app/src/main/java/h_mal/appttude/com/driver/ui/.idea/dictionaries b/app/src/main/java/h_mal/appttude/com/driver/ui/.idea/dictionaries deleted file mode 100644 index ed3680a..0000000 --- a/app/src/main/java/h_mal/appttude/com/driver/ui/.idea/dictionaries +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/java/h_mal/appttude/com/driver/ui/.idea/kotlinc.xml b/app/src/main/java/h_mal/appttude/com/driver/ui/.idea/kotlinc.xml deleted file mode 100644 index 8b7f4af..0000000 --- a/app/src/main/java/h_mal/appttude/com/driver/ui/.idea/kotlinc.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/java/h_mal/appttude/com/driver/ui/.idea/misc.xml b/app/src/main/java/h_mal/appttude/com/driver/ui/.idea/misc.xml deleted file mode 100644 index 51300e5..0000000 --- a/app/src/main/java/h_mal/appttude/com/driver/ui/.idea/misc.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/java/h_mal/appttude/com/driver/ui/.idea/modules.xml b/app/src/main/java/h_mal/appttude/com/driver/ui/.idea/modules.xml deleted file mode 100644 index f16767d..0000000 --- a/app/src/main/java/h_mal/appttude/com/driver/ui/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/java/h_mal/appttude/com/driver/ui/.idea/vcs.xml b/app/src/main/java/h_mal/appttude/com/driver/ui/.idea/vcs.xml deleted file mode 100644 index 07117e4..0000000 --- a/app/src/main/java/h_mal/appttude/com/driver/ui/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/java/h_mal/appttude/com/driver/ui/permission/DeclarationBuilder.kt b/app/src/main/java/h_mal/appttude/com/driver/ui/permission/DeclarationBuilder.kt new file mode 100644 index 0000000..feba9e5 --- /dev/null +++ b/app/src/main/java/h_mal/appttude/com/driver/ui/permission/DeclarationBuilder.kt @@ -0,0 +1,18 @@ +package h_mal.appttude.com.driver.ui.permission + +import android.content.Context +import android.text.Html +import androidx.annotation.StringRes + +interface DeclarationBuilder { + val link: String + val message: String + + fun Context.readFromResources(@StringRes id: Int) = resources.getString(id) + + fun buildMessage(): CharSequence? { + val link1 = "here" + val message = "$message See my privacy policy: $link1" + return Html.fromHtml(message, Html.FROM_HTML_MODE_LEGACY) + } +} \ No newline at end of file diff --git a/app/src/main/java/h_mal/appttude/com/driver/ui/permission/PermissionsDeclarationDialog.kt b/app/src/main/java/h_mal/appttude/com/driver/ui/permission/PermissionsDeclarationDialog.kt new file mode 100644 index 0000000..2c74d82 --- /dev/null +++ b/app/src/main/java/h_mal/appttude/com/driver/ui/permission/PermissionsDeclarationDialog.kt @@ -0,0 +1,46 @@ +package h_mal.appttude.com.driver.ui.permission + +import android.content.Context +import android.text.method.LinkMovementMethod +import android.view.View +import android.widget.TextView +import androidx.appcompat.app.AlertDialog + + +class PermissionsDeclarationDialog(context: Context) : BaseDeclarationDialog(context) { + + override val link: String = "https://sites.google.com/view/hmaldev/home/choice-cars" + override val message: String = + "Storage is required to access images on the devices" +} + +abstract class BaseDeclarationDialog(val context: Context) : DeclarationBuilder { + abstract override val link: String + abstract override val message: String + + lateinit var dialog: AlertDialog + + fun showDialog(agreeCallback: () -> Unit = { }, disagreeCallback: () -> Unit = { }) { + val myMessage = buildMessage() + + val builder = AlertDialog.Builder(context) + .setPositiveButton("agree") { _, _ -> + agreeCallback() + } + .setNegativeButton("disagree") { _, _ -> + disagreeCallback() + } + .setMessage(myMessage) + .setCancelable(false) + + dialog = builder.create() + dialog.show() + + // Make the textview clickable. Must be called after show() + val msgTxt = dialog.findViewById(android.R.id.message) as TextView? + msgTxt?.movementMethod = LinkMovementMethod.getInstance() + } + + fun dismiss() = dialog.dismiss() +} + diff --git a/app/src/main/java/h_mal/appttude/com/driver/ui/update/UpdateActivity.kt b/app/src/main/java/h_mal/appttude/com/driver/ui/update/UpdateActivity.kt index ea00689..520252e 100644 --- a/app/src/main/java/h_mal/appttude/com/driver/ui/update/UpdateActivity.kt +++ b/app/src/main/java/h_mal/appttude/com/driver/ui/update/UpdateActivity.kt @@ -1,7 +1,8 @@ package h_mal.appttude.com.driver.ui.update import h_mal.appttude.com.driver.base.BaseActivity -import h_mal.appttude.com.driver.data.FirebaseCompletion +import h_mal.appttude.com.driver.data.FirebaseCompletion.Changed +import h_mal.appttude.com.driver.data.FirebaseCompletion.ProfileDeleted import h_mal.appttude.com.driver.databinding.UpdateActivityBinding import h_mal.appttude.com.driver.viewmodels.UpdateUserViewModel @@ -10,7 +11,8 @@ class UpdateActivity : BaseActivity( override fun onSuccess(data: Any?) { super.onSuccess(data) when (data) { - is FirebaseCompletion.Changed -> showToast(data.message) + is Changed -> showSnackBar(data.message) + is ProfileDeleted -> showToast(data.message) } } } \ No newline at end of file diff --git a/app/src/main/java/h_mal/appttude/com/driver/ui/update/UpdateProfileFragment.kt b/app/src/main/java/h_mal/appttude/com/driver/ui/update/UpdateProfileFragment.kt index acd6984..1adbab3 100644 --- a/app/src/main/java/h_mal/appttude/com/driver/ui/update/UpdateProfileFragment.kt +++ b/app/src/main/java/h_mal/appttude/com/driver/ui/update/UpdateProfileFragment.kt @@ -1,20 +1,18 @@ package h_mal.appttude.com.driver.ui.update -import android.Manifest.permission.READ_EXTERNAL_STORAGE import android.net.Uri import androidx.core.widget.doAfterTextChanged import com.google.firebase.auth.FirebaseUser -import h_mal.appttude.com.driver.base.BaseFragment +import h_mal.appttude.com.driver.base.ImageSelectorFragment import h_mal.appttude.com.driver.databinding.FragmentUpdateProfileBinding -import h_mal.appttude.com.driver.utils.PermissionsUtils.askForPermissions import h_mal.appttude.com.driver.utils.setEnterPressedListener import h_mal.appttude.com.driver.utils.setGlideImage import h_mal.appttude.com.driver.viewmodels.UpdateUserViewModel const val TAG_CONST = "non-user" -private const val IMAGE_PERMISSION_RESULT = 402 -class UpdateProfileFragment : BaseFragment() { +class UpdateProfileFragment : + ImageSelectorFragment() { private var imageChangeListener: Boolean = false private var nameChangeListener: Boolean = false @@ -35,11 +33,7 @@ class UpdateProfileFragment : BaseFragment, - grantResults: IntArray - ) = onPermissionRequest(requestCode, IMAGE_PERMISSION_RESULT, grantResults) { - openGalleryForImage() - } - - override fun onSuccess(data: Any?) { super.onSuccess(data) if (data is FirebaseUser) setFields(data) diff --git a/app/src/main/java/h_mal/appttude/com/driver/utils/DateUtils.kt b/app/src/main/java/h_mal/appttude/com/driver/utils/DateUtils.kt index c8fef1f..63cc2ac 100644 --- a/app/src/main/java/h_mal/appttude/com/driver/utils/DateUtils.kt +++ b/app/src/main/java/h_mal/appttude/com/driver/utils/DateUtils.kt @@ -1,10 +1,13 @@ package h_mal.appttude.com.driver.utils -import android.icu.util.Calendar +import h_mal.appttude.com.driver.application.GLOBAL_FORMAT +import org.joda.time.LocalDate +import org.joda.time.format.DateTimeFormat import java.text.ParseException import java.text.SimpleDateFormat import java.util.* + object DateUtils { fun getDateTimeStamp(): String { @@ -27,26 +30,19 @@ object DateUtils { private fun getSimpleDateFormat(format: String) = SimpleDateFormat(format, Locale.getDefault()) - fun parseDateStringIntoCalender(dateString: String, format: String): Calendar? { - val dateFormat = getSimpleDateFormat(format) - val calendar = Calendar.getInstance() - return try { - calendar.time = dateFormat.parse(dateString) - calendar - } catch (e: Exception) { - null + fun parseDateStringIntoCalender(dateString: String, format: String = GLOBAL_FORMAT): LocalDate { + if (dateString.isBlank()) { + return LocalDate.now() } + val dtf = DateTimeFormat.forPattern(format) + return dtf.parseLocalDate(dateString) } - fun parseCalenderIntoDateString(calendar: Calendar, format: String): String? { - val date = calendar.time - val dateFormat = getSimpleDateFormat(format) - - return try { - dateFormat.format(date) - } catch (e: ParseException) { - e.printStackTrace() - null - } + fun getDateString(year: Int, month: Int, dayOfMonth: Int): String { + val date = LocalDate.now() + .withYear(year) + .withMonthOfYear(month + 1) + .withDayOfMonth(dayOfMonth) + return date.toString(GLOBAL_FORMAT) } } diff --git a/app/src/main/java/h_mal/appttude/com/driver/utils/Extensions.kt b/app/src/main/java/h_mal/appttude/com/driver/utils/Extensions.kt index fbd64b5..215f8b6 100644 --- a/app/src/main/java/h_mal/appttude/com/driver/utils/Extensions.kt +++ b/app/src/main/java/h_mal/appttude/com/driver/utils/Extensions.kt @@ -5,7 +5,7 @@ package h_mal.appttude.com.driver.utils * * @sample #boolean.isTrue{ #Do something when its true } */ -inline fun Boolean.isTrue(block: () -> Unit){ +inline fun Boolean.isTrue(block: () -> Unit) { if (this) { block() } @@ -16,7 +16,7 @@ inline fun Boolean.isTrue(block: () -> Unit){ * * @sample #nullable.isNotNull{i -> i.doSomethingSinceItsNotNull() } */ -inline fun T?.isNotNull(block: (T) -> R): R?{ +inline fun T?.isNotNull(block: (T) -> R): R? { return if (this != null) { block(this) } else { diff --git a/app/src/main/java/h_mal/appttude/com/driver/utils/FirebaseException.kt b/app/src/main/java/h_mal/appttude/com/driver/utils/FirebaseException.kt index 5949f2a..43d85c4 100644 --- a/app/src/main/java/h_mal/appttude/com/driver/utils/FirebaseException.kt +++ b/app/src/main/java/h_mal/appttude/com/driver/utils/FirebaseException.kt @@ -15,31 +15,43 @@ class FirebaseException( enum class Status(private val code: Int) { DATA_STALE(-1), + /** The server indicated that this operation failed */ OPERATION_FAILED(-2), + /** This client does not have permission to perform this operation */ PERMISSION_DENIED(-3), + /** The operation had to be aborted due to a network disconnect */ DISCONNECTED(-4), + /** The supplied auth token has expired */ - EXPIRED_TOKEN (-6), + EXPIRED_TOKEN(-6), + /** * The specified authentication token is invalid. This can occur when the token is malformed, * expired, or the secret that was used to generate it has been revoked. */ INVALID_TOKEN(-7), + /** The transaction had too many retries */ MAX_RETRIES(-8), + /** The transaction was overridden by a subsequent set */ OVERRIDDEN_BY_SET(-9), + /** The service is unavailable */ UNAVAILABLE(-10), + /** An exception occurred in user code */ USER_CODE_EXCEPTION(-11), + /** The operation could not be performed due to a network error. */ NETWORK_ERROR(-24), + /** The write was canceled locally */ WRITE_CANCELED(-25), + /** * An unknown error occurred. Please refer to the error message and error details for more * information. diff --git a/app/src/main/java/h_mal/appttude/com/driver/utils/FirebaseUtils.kt b/app/src/main/java/h_mal/appttude/com/driver/utils/FirebaseUtils.kt index 00b35bf..3e5df12 100644 --- a/app/src/main/java/h_mal/appttude/com/driver/utils/FirebaseUtils.kt +++ b/app/src/main/java/h_mal/appttude/com/driver/utils/FirebaseUtils.kt @@ -37,6 +37,7 @@ suspend inline fun DatabaseReference.getDataFromDatabaseRef(): is EventResponse.Changed -> { response.snapshot.getValue(T::class.java) } + is EventResponse.Cancelled -> { throw FirebaseException(response.error) } @@ -53,17 +54,19 @@ suspend inline fun DatabaseReference.getListDataFromDatabaseRe is EventResponse.Changed -> { response.snapshot.children.map { it.getValue(T::class.java) } } + is EventResponse.Cancelled -> { throw FirebaseException(response.error) } } } -suspend fun DatabaseReference.getDataFromDatabaseRef(clazz : Class): T? { +suspend fun DatabaseReference.getDataFromDatabaseRef(clazz: Class): T? { return when (val response: EventResponse = singleValueEvent()) { is EventResponse.Changed -> { response.snapshot.getValue(clazz) } + is EventResponse.Cancelled -> { throw FirebaseException(response.error) } diff --git a/app/src/main/java/h_mal/appttude/com/driver/utils/GenericsHelper.kt b/app/src/main/java/h_mal/appttude/com/driver/utils/GenericsHelper.kt index 24238dd..421815d 100644 --- a/app/src/main/java/h_mal/appttude/com/driver/utils/GenericsHelper.kt +++ b/app/src/main/java/h_mal/appttude/com/driver/utils/GenericsHelper.kt @@ -19,7 +19,7 @@ object GenericsHelper { * * @sample inflateBindingByType(getGenericClassAt(0), layoutInflater) */ - fun inflateBindingByType( + fun inflateBindingByType( genericClassAt: KClass, layoutInflater: LayoutInflater ): VB = try { @@ -30,12 +30,12 @@ object GenericsHelper { && viewBinding.parameterTypes.getOrNull(0) == LayoutInflater::class.java }.invoke(null, layoutInflater) as VB } catch (exception: Exception) { - println ("generic class failed at = $genericClassAt") + println("generic class failed at = $genericClassAt") exception.printStackTrace() throw IllegalStateException("Can not inflate binding from generic") } - fun LayoutInflater.inflateBindingByType( + fun LayoutInflater.inflateBindingByType( container: ViewGroup?, genericClassAt: KClass ): VB = try { diff --git a/app/src/main/java/h_mal/appttude/com/driver/utils/PermissionsUtils.kt b/app/src/main/java/h_mal/appttude/com/driver/utils/PermissionsUtils.kt index 32ec414..5bc2fc9 100644 --- a/app/src/main/java/h_mal/appttude/com/driver/utils/PermissionsUtils.kt +++ b/app/src/main/java/h_mal/appttude/com/driver/utils/PermissionsUtils.kt @@ -9,7 +9,6 @@ import android.provider.Settings import androidx.appcompat.app.AlertDialog import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat -import androidx.fragment.app.Fragment object PermissionsUtils { @@ -39,12 +38,6 @@ object PermissionsUtils { return true } - fun Fragment.askForPermissions(permission: String, requestCode: Int): Boolean = - requireActivity().askForPermissions(permission, requestCode) - - fun isGranted(grantResults: IntArray): Boolean = - grantResults.getOrNull(0)?.equals(PERMISSION_GRANTED) ?: false - private fun Context.showPermissionDeniedDialog() { AlertDialog.Builder(this) .setTitle("Permission Denied") diff --git a/app/src/main/res/drawable/baseline_check_24.xml b/app/src/main/res/drawable/baseline_check_24.xml index 2501e9f..9e21ec4 100644 --- a/app/src/main/res/drawable/baseline_check_24.xml +++ b/app/src/main/res/drawable/baseline_check_24.xml @@ -1,5 +1,10 @@ - - + + diff --git a/app/src/main/res/drawable/baseline_clear_24.xml b/app/src/main/res/drawable/baseline_clear_24.xml index 70db409..49ac6f1 100644 --- a/app/src/main/res/drawable/baseline_clear_24.xml +++ b/app/src/main/res/drawable/baseline_clear_24.xml @@ -1,5 +1,10 @@ - - + + diff --git a/app/src/main/res/drawable/baseline_inbox_24.xml b/app/src/main/res/drawable/baseline_inbox_24.xml index 5857b5d..1dba458 100644 --- a/app/src/main/res/drawable/baseline_inbox_24.xml +++ b/app/src/main/res/drawable/baseline_inbox_24.xml @@ -1,5 +1,10 @@ - - + + diff --git a/app/src/main/res/drawable/ic_baseline_arrow_forward_24.xml b/app/src/main/res/drawable/ic_baseline_arrow_forward_24.xml index 02671e8..0035908 100644 --- a/app/src/main/res/drawable/ic_baseline_arrow_forward_24.xml +++ b/app/src/main/res/drawable/ic_baseline_arrow_forward_24.xml @@ -1,9 +1,9 @@ - + android:height="24dp" + android:tint="#FFFFFF" + android:viewportWidth="24" + android:viewportHeight="24"> diff --git a/app/src/main/res/drawable/ic_baseline_assignment_ind_24.xml b/app/src/main/res/drawable/ic_baseline_assignment_ind_24.xml index a0f1ea9..30504d3 100644 --- a/app/src/main/res/drawable/ic_baseline_assignment_ind_24.xml +++ b/app/src/main/res/drawable/ic_baseline_assignment_ind_24.xml @@ -1,9 +1,9 @@ - + android:height="24dp" + android:tint="#FFFFFF" + android:viewportWidth="24" + android:viewportHeight="24"> diff --git a/app/src/main/res/drawable/ic_baseline_photo_library_24.xml b/app/src/main/res/drawable/ic_baseline_photo_library_24.xml index 4f7eb78..d9e00e2 100644 --- a/app/src/main/res/drawable/ic_baseline_photo_library_24.xml +++ b/app/src/main/res/drawable/ic_baseline_photo_library_24.xml @@ -1,9 +1,9 @@ - + android:height="24dp" + android:tint="#FFFFFF" + android:viewportWidth="24" + android:viewportHeight="24"> diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index ab15e00..7c39387 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -1,7 +1,7 @@ + android:theme="@style/AppTheme.AppBarOverlay" + app:elevation="0dp"> + android:inputType="textEmailAddress" /> + android:inputType="textPassword" /> + app:layout_constraintRight_toRightOf="parent"> + android:contentDescription="@string/image_description" + android:scaleType="centerCrop" /> + android:alpha="1" + android:elevation="1dp" + android:scaleType="centerInside" + android:src="@drawable/ic_baseline_photo_library_24" + app:civ_border_width="1dp" + app:civ_circle_color="@color/colour_one" + app:civ_shadow_radius="0.5dp" /> @@ -53,24 +52,24 @@ android:id="@+id/lic_no" style="@style/EditTextStyle.Date" android:hint="@string/drivers_license_no" + android:importantForAutofill="no" android:inputType="none" - android:maxLines="1" - android:importantForAutofill="no" /> + android:maxLines="1" /> + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/til_lic_no"> + android:autofillHints="date" + android:hint="@string/license_expiry_date" /> @@ -78,10 +77,10 @@ android:id="@+id/submit" style="@style/TextButton.WithIcon" android:text="@string/submit" - app:layout_constraintTop_toBottomOf="@+id/til_submission" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/til_submission" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.8" /> diff --git a/app/src/main/res/layout/fragment_driver_profile.xml b/app/src/main/res/layout/fragment_driver_profile.xml index 0cdcd7d..532010b 100644 --- a/app/src/main/res/layout/fragment_driver_profile.xml +++ b/app/src/main/res/layout/fragment_driver_profile.xml @@ -2,13 +2,19 @@ - + + android:maxLines="1" /> @@ -67,6 +72,7 @@ android:id="@+id/address_input" style="@style/EditTextStyle" android:layout_marginBottom="12dp" + android:autofillHints="postalAddress" android:ems="10" android:gravity="top|start" android:hint="@string/address" @@ -75,8 +81,7 @@ android:maxLines="7" android:minLines="4" android:selectAllOnFocus="true" - android:singleLine="true" - android:autofillHints="postalAddress" /> + android:singleLine="true" /> @@ -86,12 +91,12 @@ android:id="@+id/postcode_input" style="@style/EditTextStyle" android:layout_marginBottom="12dp" + android:autofillHints="postalCode" android:hint="@string/postcode" android:inputType="none" android:maxLines="1" android:selectAllOnFocus="true" - android:singleLine="true" - android:autofillHints="postalCode" /> + android:singleLine="true" /> @@ -101,8 +106,8 @@ android:id="@+id/dob_input" style="@style/EditTextStyle.Date" android:layout_marginBottom="12dp" - android:hint="@string/date_of_birth" - android:autofillHints="date" /> + android:autofillHints="date" + android:hint="@string/date_of_birth" /> @@ -113,9 +118,9 @@ style="@style/EditTextStyle" android:layout_marginBottom="12dp" android:hint="@string/ni_number" - android:maxLines="1" android:importantForAutofill="no" android:inputType="none" + android:maxLines="1" tools:ignore="TextFields" /> @@ -126,8 +131,8 @@ android:id="@+id/date_first" style="@style/EditTextStyle.Date" android:layout_marginBottom="12dp" - android:hint="@string/date_first_available" - android:autofillHints="date" /> + android:autofillHints="date" + android:hint="@string/date_first_available" /> diff --git a/app/src/main/res/layout/fragment_forgot_password.xml b/app/src/main/res/layout/fragment_forgot_password.xml index de856a4..a74ae2d 100644 --- a/app/src/main/res/layout/fragment_forgot_password.xml +++ b/app/src/main/res/layout/fragment_forgot_password.xml @@ -37,9 +37,9 @@ + android:inputType="textEmailAddress" /> + android:contentDescription="@string/floating_action_button" + android:src="@drawable/ic_file_download_black_24dp" /> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_insurance.xml b/app/src/main/res/layout/fragment_insurance.xml index ffa2b0c..ea23678 100644 --- a/app/src/main/res/layout/fragment_insurance.xml +++ b/app/src/main/res/layout/fragment_insurance.xml @@ -10,12 +10,12 @@ android:id="@+id/carouselView" android:layout_width="match_parent" android:layout_height="200dp" - app:layout_constraintLeft_toLeftOf="parent" - app:layout_constraintRight_toRightOf="parent" - app:layout_constraintBottom_toTopOf="@id/uploadInsurance" android:layout_marginBottom="12dp" app:autoPlay="false" app:fillColor="#FFFFFFFF" + app:layout_constraintBottom_toTopOf="@id/uploadInsurance" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" app:pageColor="#00000000" app:radius="6dp" app:strokeColor="#FF777777" @@ -41,11 +41,11 @@ android:id="@+id/insurer" style="@style/EditTextStyle" android:hint="@string/insurer" + android:importantForAutofill="no" android:inputType="none" android:maxLines="1" android:selectAllOnFocus="true" - android:singleLine="true" - android:importantForAutofill="no" /> + android:singleLine="true" /> @@ -61,9 +61,9 @@ style="@style/EditTextStyle.Date" android:layout_width="match_parent" android:layout_height="wrap_content" - android:inputType="date" android:hint="@string/insurance_expiry" - android:importantForAutofill="no" /> + android:importantForAutofill="no" + android:inputType="date" /> + android:layout_width="match_parent" + android:layout_height="match_parent"> + app:layout_constraintRight_toRightOf="parent"> + tools:src="@drawable/choice_img_round" /> + android:text="@string/upload_logbook" + app:layout_constraintBottom_toTopOf="@id/til_v5c" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" /> + app:layout_constraintTop_toTopOf="parent"> + android:importantForAutofill="no" + android:inputType="none" /> + app:layout_constraintTop_toBottomOf="@+id/til_v5c" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="0.8"> diff --git a/app/src/main/res/layout/fragment_login.xml b/app/src/main/res/layout/fragment_login.xml index bbf0fb5..6441edc 100644 --- a/app/src/main/res/layout/fragment_login.xml +++ b/app/src/main/res/layout/fragment_login.xml @@ -45,9 +45,9 @@ style="@style/EditTextStyle" android:layout_width="match_parent" android:layout_height="match_parent" + android:autofillHints="emailAddress" android:hint="@string/prompt_email" - android:inputType="textEmailAddress" - android:autofillHints="emailAddress" /> + android:inputType="textEmailAddress" /> + android:inputType="textPassword" /> + app:layout_constraintRight_toRightOf="parent"> + tools:src="@drawable/choice_img_round" /> + app:layout_constraintStart_toStartOf="parent" /> + app:layout_constraintTop_toTopOf="parent"> + android:autofillHints="" + android:hint="@string/mot_expiry_date" /> diff --git a/app/src/main/res/layout/fragment_private_hire_license.xml b/app/src/main/res/layout/fragment_private_hire_license.xml index ab5f92d..c27fdd2 100644 --- a/app/src/main/res/layout/fragment_private_hire_license.xml +++ b/app/src/main/res/layout/fragment_private_hire_license.xml @@ -9,8 +9,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:maxWidth="350dp" android:layout_marginBottom="12dp" + android:maxWidth="350dp" app:cardCornerRadius="28dp" app:cardElevation="0dp" app:layout_constraintBottom_toTopOf="@id/uploadphlic" @@ -22,9 +22,9 @@ android:layout_width="match_parent" android:layout_height="200dp" android:adjustViewBounds="true" + android:contentDescription="@string/image_description" android:scaleType="centerCrop" - tools:src="@drawable/choice_img" - android:contentDescription="@string/image_description" /> + tools:src="@drawable/choice_img" /> + tools:text="987651" /> @@ -64,9 +64,9 @@ + android:hint="@string/private_hire_license_expiry" + tools:text="30/12/2018" /> @@ -79,6 +79,6 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/til_submission" app:layout_constraintTop_toTopOf="parent" - app:layout_constraintVertical_bias="0.8"/> + app:layout_constraintVertical_bias="0.8" /> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_private_hire_vehicle.xml b/app/src/main/res/layout/fragment_private_hire_vehicle.xml index 921a962..db03ac3 100644 --- a/app/src/main/res/layout/fragment_private_hire_vehicle.xml +++ b/app/src/main/res/layout/fragment_private_hire_vehicle.xml @@ -20,9 +20,9 @@ android:layout_width="200dp" android:layout_height="200dp" android:adjustViewBounds="true" + android:contentDescription="@string/image_description" android:scaleType="centerCrop" - tools:src="@drawable/choice_img_round" - android:contentDescription="@string/image_description" /> + tools:src="@drawable/choice_img_round" /> + android:autofillHints="date" + android:hint="@string/private_hire_certificate_expiry" /> diff --git a/app/src/main/res/layout/fragment_register.xml b/app/src/main/res/layout/fragment_register.xml index 585d5f1..8e57d20 100644 --- a/app/src/main/res/layout/fragment_register.xml +++ b/app/src/main/res/layout/fragment_register.xml @@ -46,34 +46,35 @@ + app:layout_constraintStart_toStartOf="parent"> + android:inputType="textPersonName" /> + app:layout_constraintTop_toBottomOf="@+id/til_name" + app:layout_constraintTop_toTopOf="parent"> + + android:inputType="textEmailAddress" /> + + android:inputType="textPassword" /> + + android:inputType="textPassword" /> diff --git a/app/src/main/res/layout/fragment_update_email.xml b/app/src/main/res/layout/fragment_update_email.xml index 9c57b47..8fcb1e8 100644 --- a/app/src/main/res/layout/fragment_update_email.xml +++ b/app/src/main/res/layout/fragment_update_email.xml @@ -8,10 +8,10 @@ + app:layout_constraintStart_toStartOf="parent"> + android:autofillHints="emailAddress" + android:hint="@string/prompt_email" + android:inputType="textEmailAddress" /> + app:layout_constraintTop_toTopOf="parent"> + android:inputType="textPassword" /> + app:layout_constraintTop_toBottomOf="@+id/til_password_top" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="0.8" /> diff --git a/app/src/main/res/layout/fragment_update_password.xml b/app/src/main/res/layout/fragment_update_password.xml index 38aab78..55ba54a 100644 --- a/app/src/main/res/layout/fragment_update_password.xml +++ b/app/src/main/res/layout/fragment_update_password.xml @@ -31,33 +31,33 @@ + app:layout_constraintStart_toStartOf="parent"> + android:inputType="textEmailAddress" /> + app:layout_constraintTop_toBottomOf="@+id/til_name" + app:layout_constraintTop_toTopOf="parent"> + android:inputType="textPassword" /> + android:inputType="textPassword" /> + app:layout_constraintTop_toBottomOf="@+id/til_new_password" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="0.8"> diff --git a/app/src/main/res/layout/fragment_update_profile.xml b/app/src/main/res/layout/fragment_update_profile.xml index 5c8402d..e2d05c5 100644 --- a/app/src/main/res/layout/fragment_update_profile.xml +++ b/app/src/main/res/layout/fragment_update_profile.xml @@ -9,8 +9,8 @@ + app:layout_constraintTop_toTopOf="parent"> + android:inputType="textPersonName" /> + android:layout_marginBottom="12dp" + android:autofillHints="none" + android:hint="@string/car_reg" + android:inputType="textCapCharacters" /> @@ -26,12 +26,12 @@ + android:maxLines="1" /> @@ -39,12 +39,12 @@ + android:maxLines="1" /> @@ -52,12 +52,12 @@ + android:maxLines="1" /> @@ -65,15 +65,15 @@ + android:maxLines="1" /> @@ -81,7 +81,9 @@ + android:singleLine="true" /> @@ -100,16 +100,16 @@ + android:singleLine="true" /> @@ -117,10 +117,10 @@ + android:layout_marginBottom="12dp" + android:autofillHints="date" + android:hint="@string/car_start_date" /> @@ -129,17 +129,17 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="12dp" - android:hint="@string/vehicle_seized" android:buttonTint="@color/colour_eight" + android:hint="@string/vehicle_seized" android:padding="12dp" android:textSize="18sp" /> + android:text="@string/submit" /> \ No newline at end of file diff --git a/app/src/main/res/layout/home_buttons_container.xml b/app/src/main/res/layout/home_buttons_container.xml index 61fab04..b01206d 100644 --- a/app/src/main/res/layout/home_buttons_container.xml +++ b/app/src/main/res/layout/home_buttons_container.xml @@ -3,8 +3,8 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="vertical" android:layout_marginBottom="64dp" + android:orientation="vertical" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"> @@ -12,8 +12,8 @@ + android:layout_marginBottom="12dp" + android:text="@string/driver_profile" /> + android:textAppearance="@style/TextAppearance.AppCompat.Body1" + android:textSize="18sp" /> + app:layout_constraintTop_toTopOf="parent" /> \ No newline at end of file diff --git a/app/src/main/res/layout/update_activity.xml b/app/src/main/res/layout/update_activity.xml index 451bc4f..cd9ce92 100644 --- a/app/src/main/res/layout/update_activity.xml +++ b/app/src/main/res/layout/update_activity.xml @@ -1,7 +1,7 @@ diff --git a/app/src/main/res/layout/update_overview_fragment.xml b/app/src/main/res/layout/update_overview_fragment.xml index 562503e..31015f5 100644 --- a/app/src/main/res/layout/update_overview_fragment.xml +++ b/app/src/main/res/layout/update_overview_fragment.xml @@ -26,22 +26,22 @@ app:layout_constraintTop_toBottomOf="@+id/login_title_tv" /> + app:layout_constraintStart_toStartOf="parent" /> + app:layout_constraintStart_toStartOf="parent" /> diff --git a/app/src/main/res/navigation/auth_navigation.xml b/app/src/main/res/navigation/auth_navigation.xml index a62d468..e487946 100644 --- a/app/src/main/res/navigation/auth_navigation.xml +++ b/app/src/main/res/navigation/auth_navigation.xml @@ -45,9 +45,9 @@ app:destination="@id/loginFragment" app:enterAnim="@anim/nav_default_pop_enter_anim" app:exitAnim="@anim/nav_default_pop_exit_anim" + app:launchSingleTop="true" app:popEnterAnim="@anim/nav_default_pop_enter_anim" app:popExitAnim="@anim/nav_default_pop_exit_anim" - app:launchSingleTop="true" app:popUpTo="@id/auth_navigation" app:popUpToInclusive="true" /> diff --git a/app/src/testDebug/java/driver/ExampleUnitTest.java b/app/src/testDebug/java/driver/ExampleUnitTest.java deleted file mode 100644 index 8be5855..0000000 --- a/app/src/testDebug/java/driver/ExampleUnitTest.java +++ /dev/null @@ -1,17 +0,0 @@ -package driver; - -import static org.junit.Assert.assertEquals; - -import org.junit.Test; - -/** - * Example local unit test, which will execute on the development machine (host). - * - * @see Testing documentation - */ -public class ExampleUnitTest { - @Test - public void addition_isCorrect() { - assertEquals(4, 2 + 2); - } -} \ No newline at end of file diff --git a/storage.rules b/storage.rules index 9f33d22..776621d 100644 --- a/storage.rules +++ b/storage.rules @@ -2,7 +2,7 @@ rules_version = '2'; service firebase.storage { match /b/{bucket}/o { match /{allPaths=**} { - allow read, write: if false; + allow read, write: if request.auth != null; } } }