Firebase emulator testing (#9)

- Firebase emulator added
 - Update to Espresso tests
 - Updated gradle dependencies for espresso
 - Updated config.yml
 - Updated android gradle version
This commit is contained in:
2023-03-17 18:37:20 +00:00
committed by GitHub
parent 88604e6970
commit 7f4060f1c2
53 changed files with 491 additions and 183 deletions

View File

@@ -37,17 +37,43 @@ jobs:
# The next step will run the unit tests # The next step will run the unit tests
- android/run-tests: - android/run-tests:
test-command: ./gradlew testDriverDebugUnitTest --continue test-command: ./gradlew testDriverDebugUnitTest --continue
# Install Firebase tools needed for firebase emulator
# Then start the emulator and run the Instrumentation tests! - run:
# - android/start-emulator-and-run-tests: name: Install firebase tools
# test-command: ./gradlew connectedDebugAndroidTest command: |
# system-image: system-images;android-25;google_apis;x86 curl -sL firebase.tools | bash
# Then start firebase emulator in the background
- run:
name: Start firebase emulator
command: |
firebase emulators:start
background: true
# Then start the emulator and run the Instrumentation tests!
- android/start-emulator-and-run-tests:
post-emulator-launch-assemble-command: ./gradlew assembleDriverDebugAndroidTest
test-command: ./gradlew connectedDriverDebugAndroidTest
system-image: system-images;android-25;google_apis;x86
# And finally run the release build # And finally run the release build
# - run: # - run:
# name: Assemble release build # name: Assemble release build
# command: | # command: |
# ./gradlew assembleDriverRelease # ./gradlew assembleDriverRelease
# Then publish the artifacts of the Instrumentation tests!
- store_artifacts:
path: app/build/reports/androidTests/connected
destination: reports
# Then publish the artifacts of the Firebase emulator logs!
- run:
name: save firebase emulator logs
command: |
mkdir -p tmp/firebase_logs
cp *.log tmp/firebase_logs
- store_artifacts:
path: tmp/firebase_logs
destination: logs
# Then publish the results of the Instrumentation tests!
- store_test_results:
path: app/build/outputs/androidTest-results/connected
# Invoke jobs via workflows # Invoke jobs via workflows
# See: https://circleci.com/docs/2.0/configuration-reference/#workflows # See: https://circleci.com/docs/2.0/configuration-reference/#workflows

5
.firebaserc Normal file
View File

@@ -0,0 +1,5 @@
{
"projects": {
"default": "driver-8f4a1"
}
}

2
.gitignore vendored
View File

@@ -13,3 +13,5 @@
/build /build
/captures /captures
.externalNativeBuild .externalNativeBuild
*.log
local

2
.idea/misc.xml generated
View File

@@ -39,7 +39,7 @@
</value> </value>
</option> </option>
</component> </component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_17_PREVIEW" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" /> <output url="file://$PROJECT_DIR$/build/classes" />
</component> </component>
<component name="ProjectType"> <component name="ProjectType">

View File

@@ -27,6 +27,20 @@ android {
versionCode 6 versionCode 6
versionName "1.6" versionName "1.6"
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
boolean state = project.rootProject.file('local.properties').canRead()
buildConfigField "boolean", "LocalState", "$state"
}
android {
sourceSets {
test {
resources.srcDirs += ['src/test/resources']
}
androidTest {
resources.srcDirs += ['src/androidTest/resources']
}
}
} }
signingConfigs { signingConfigs {
@@ -94,42 +108,47 @@ dependencies {
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1"
implementation 'androidx.viewpager:viewpager:1.0.0' implementation 'androidx.viewpager:viewpager:1.0.0'
testImplementation "junit:junit:4.13.2"
androidTestImplementation "androidx.test.ext:junit:1.1.5"
androidTestImplementation "androidx.test.espresso:espresso-core:3.5.1"
androidTestImplementation "androidx.test:rules:1.5.0"
implementation 'androidx.test.espresso:espresso-idling-resource:3.5.1'
implementation "androidx.legacy:legacy-support-v4:1.0.0" implementation "androidx.legacy:legacy-support-v4:1.0.0"
// Google play services testImplementation "junit:junit:4.13.2"
/ * Android Espresso */
def testJunitVersion = "1.1.5"
def testRunnerVersion = "1.5.2"
def espressoVersion = "3.5.1"
androidTestImplementation "androidx.test.ext:junit:$testJunitVersion"
androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion"
androidTestImplementation "androidx.test.espresso.idling:idling-concurrent:$espressoVersion"
implementation "androidx.test.espresso:espresso-idling-resource:$espressoVersion"
androidTestImplementation "androidx.test:runner:$testRunnerVersion"
/ * Google play services */
implementation "com.google.android.gms:play-services-auth:20.4.1" implementation "com.google.android.gms:play-services-auth:20.4.1"
// Google firebase / * Google firebase */
def firebaseVer = "20.1.0" def firebaseCore = "21.1.1"
implementation "com.google.firebase:firebase-core:$firebaseVer" def firebaseAuth = "20.0.0"
implementation "com.google.firebase:firebase-auth:21.0.0" def firebaseStorage = "20.0.0"
implementation "com.google.firebase:firebase-storage:$firebaseVer" def firebaseDatabase = "19.4.0"
implementation "com.google.firebase:firebase-database:$firebaseVer" implementation "com.google.firebase:firebase-core:$firebaseCore"
// Photoviewer implementation "com.google.firebase:firebase-auth:$firebaseAuth"
implementation "com.google.firebase:firebase-storage:$firebaseStorage"
implementation "com.google.firebase:firebase-database:$firebaseDatabase"
/ * Photoviewer */
implementation "com.github.chrisbanes:PhotoView:2.1.0" implementation "com.github.chrisbanes:PhotoView:2.1.0"
/* Picasso photo loader */ / * Picasso photo loader */
implementation "com.squareup.picasso:picasso:2.71828" implementation "com.squareup.picasso:picasso:2.71828"
/* Gson */ / * Gson */
implementation "com.google.code.gson:gson:2.8.9" implementation "com.google.code.gson:gson:2.8.9"
/* coroutines support for firebase operations */ / * coroutines support for firebase operations */
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.6.1" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.6.1"
/ * Circle Image View */
// Circle Image View
implementation "com.mikhaellopez:circularimageview:4.2.0" implementation "com.mikhaellopez:circularimageview:4.2.0"
/ * Kodein Dependency Injection */
//Kodein Dependency Injection
def kodein_version = "6.2.1" def kodein_version = "6.2.1"
implementation "org.kodein.di:kodein-di-generic-jvm:$kodein_version" implementation "org.kodein.di:kodein-di-generic-jvm:$kodein_version"
implementation "org.kodein.di:kodein-di-framework-android-x:$kodein_version" implementation "org.kodein.di:kodein-di-framework-android-x:$kodein_version"
/ * Image Carousal */
/* Image Carousal */
implementation 'com.synnapps:carouselview:0.1.5' implementation 'com.synnapps:carouselview:0.1.5'
/ * Glide */ / * Glide */
implementation 'com.github.bumptech.glide:glide:4.12.0' implementation 'com.github.bumptech.glide:glide:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
/ * OKHttp */
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
} }

View File

@@ -6,15 +6,15 @@ import androidx.test.espresso.Espresso.onData
import androidx.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.ViewInteraction import androidx.test.espresso.ViewInteraction
import androidx.test.espresso.action.ViewActions import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.assertion.ViewAssertions
import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withId
import org.hamcrest.CoreMatchers.* import org.hamcrest.CoreMatchers.allOf
import org.hamcrest.CoreMatchers.anything
open class BaseTestRobot { open class BaseTestRobot {
fun fillEditText(resId: Int, text: String): ViewInteraction = fun fillEditText(resId: Int, text: String?): ViewInteraction =
onView(withId(resId)).perform(ViewActions.replaceText(text), ViewActions.closeSoftKeyboard()) onView(withId(resId)).perform(ViewActions.replaceText(text), ViewActions.closeSoftKeyboard())
fun clickButton(resId: Int): ViewInteraction = onView((withId(resId))).perform(ViewActions.click()) fun clickButton(resId: Int): ViewInteraction = onView((withId(resId))).perform(ViewActions.click())
@@ -22,7 +22,7 @@ open class BaseTestRobot {
fun textView(resId: Int): ViewInteraction = onView(withId(resId)) fun textView(resId: Int): ViewInteraction = onView(withId(resId))
fun matchText(viewInteraction: ViewInteraction, text: String): ViewInteraction = viewInteraction fun matchText(viewInteraction: ViewInteraction, text: String): ViewInteraction = viewInteraction
.check(ViewAssertions.matches(ViewMatchers.withText(text))) .check(matches(ViewMatchers.withText(text)))
fun matchText(resId: Int, text: String): ViewInteraction = matchText(textView(resId), text) fun matchText(resId: Int, text: String): ViewInteraction = matchText(textView(resId), text)

View File

@@ -1,38 +1,60 @@
package h_mal.appttude.com package h_mal.appttude.com
import android.view.View
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity import androidx.test.core.app.ActivityScenario
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry import androidx.test.espresso.IdlingRegistry
import androidx.test.rule.ActivityTestRule import androidx.test.espresso.IdlingResource
import h_mal.appttude.com.espresso.IdlingResourceClass import androidx.test.espresso.UiController
import org.junit.AfterClass import androidx.test.espresso.ViewAction
import org.junit.BeforeClass import androidx.test.espresso.matcher.ViewMatchers.isRoot
import org.junit.Ignore import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Rule import h_mal.appttude.com.base.BaseActivity
import org.hamcrest.Matcher
import org.junit.After
import org.junit.Before
abstract class BaseUiTest<T : AppCompatActivity> {
@Ignore open class BaseUiTest<T : BaseActivity<*>>(
abstract fun getApplicationClass(): Class<T> private val activity: Class<T>
) {
@get:Rule private lateinit var mActivityScenarioRule: ActivityScenario<T>
var mActivityTestRule = ActivityTestRule(getApplicationClass()) private var mIdlingResource: IdlingResource? = null
companion object { @Before
@BeforeClass fun setup() {
@JvmStatic beforeLaunch()
fun setUp() { mActivityScenarioRule = ActivityScenario.launch(activity)
IdlingRegistry.getInstance().register(IdlingResourceClass.countingIdlingResource) mActivityScenarioRule.onActivity {
} mIdlingResource = it.getIdlingResource()!!
IdlingRegistry.getInstance().register(mIdlingResource)
@AfterClass
@JvmStatic
fun tearDown() {
IdlingRegistry.getInstance().unregister(IdlingResourceClass.countingIdlingResource)
} }
} }
fun getResourceString(@StringRes stringRes: Int): String { @After
return mActivityTestRule.activity.getString(stringRes) fun tearDown() {
mIdlingResource?.let {
IdlingRegistry.getInstance().unregister(it)
}
} }
fun getResourceString(@StringRes stringRes: Int): String {
return InstrumentationRegistry.getInstrumentation().targetContext.resources.getString(
stringRes
)
}
fun waitFor(delay: Long) {
onView(isRoot()).perform(object : ViewAction {
override fun getConstraints(): Matcher<View> = isRoot()
override fun getDescription(): String? = "wait for $delay milliseconds"
override fun perform(uiController: UiController, v: View?) {
uiController.loopMainThreadForAtLeast(delay)
}
})
}
open fun beforeLaunch() {}
} }

View File

@@ -0,0 +1,9 @@
package h_mal.appttude.com
private const val apiKey = "test_key"
const val signUpFirebase = "http://identitytoolkit.googleapis.com/v1/accounts:signUp?key=$apiKey"
const val deleteAccountFirebase = "http://10.0.2.2:9099/identitytoolkit.googleapis.com/v1/accounts:delete?key=$apiKey"
const val USER_PASSWORD = "LetMeIn123!"

View File

@@ -0,0 +1,87 @@
package h_mal.appttude.com
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.FirebaseDatabase
import com.google.firebase.storage.FirebaseStorage
import h_mal.appttude.com.base.BaseActivity
import h_mal.appttude.com.data.FirebaseAuthSource
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.tasks.await
import org.junit.After
import org.junit.BeforeClass
open class FirebaseTest<T : BaseActivity<*>>(
activity: Class<T>,
private val registered: Boolean = false,
private val signedIn: Boolean = false
) : BaseUiTest<T>(activity) {
private val firebaseAuthSource by lazy { FirebaseAuthSource() }
private var email: String? = null
companion object {
/**
* Setup firebase emulators before all tests
*/
@JvmStatic
@BeforeClass
fun setupFirebase() {
val localHost = "10.0.2.2"
FirebaseAuth.getInstance().useEmulator(localHost, 9099)
FirebaseDatabase.getInstance().useEmulator(localHost, 9000)
FirebaseStorage.getInstance().useEmulator(localHost, 9199)
}
}
override fun beforeLaunch() {
if (registered) {
runBlocking {
setupUser()
}
if (!signedIn) firebaseAuthSource.logOut()
}
}
@After
fun tearDownFirebase() = runBlocking {
removeUser()
firebaseAuthSource.logOut()
}
suspend fun setupUser(
signInEmail: String = generateEmailAddress(),
password: String = USER_PASSWORD
) {
email = signInEmail
firebaseAuthSource.registerUser(signInEmail, password).await().user
}
// remove the user we created for testing
suspend fun removeUser() {
try {
getEmail()?.let {
if (firebaseAuthSource.getUser() == null) firebaseAuthSource.signIn(email = it, password = USER_PASSWORD).await()
firebaseAuthSource.reauthenticate(it, USER_PASSWORD).await()
firebaseAuthSource.deleteProfile().await()
}
} catch (e: Exception) {
e.printStackTrace()
}
}
fun generateEmailAddress(): String {
val suffix = (1000..50000).random()
email ="test-${suffix}@test-account.com"
return email!!
}
fun getEmail(): String? {
firebaseAuthSource.getUser()?.email?.let {
return it
}
return email
}
}

View File

@@ -0,0 +1,62 @@
package h_mal.appttude.com
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import kotlinx.coroutines.suspendCancellableCoroutine
import okhttp3.*
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.IOException
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
class WebUtils {
private val okHttpClient by lazy { OkHttpClient() }
suspend fun <T : Any> post(url: String, body: String): T? {
val requestBody = body.toRequestBody()
val request = Request.Builder()
.post(requestBody)
.url(url)
.build()
return okHttpClient.newCall(request).await()
}
suspend fun get(url: String): String? {
val request: Request = Request.Builder()
.url(url)
.build()
return okHttpClient.newCall(request).await()
}
private suspend fun <T> Call.await(): T? {
val objectMapper = Gson()
val typeToken: TypeToken<T> = object : TypeToken<T>() {}
return suspendCancellableCoroutine { continuation ->
enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
continuation.resume(
objectMapper.fromJson(
response.body?.string(),
typeToken.type
)
)
}
override fun onFailure(call: Call, e: IOException) {
// Don't bother with resuming the continuation if it is already cancelled.
if (continuation.isCancelled) return
continuation.resumeWithException(e)
}
})
continuation.invokeOnCancellation {
try {
cancel()
} catch (ex: Throwable) {
//Ignore cancel exception
}
}
}
}
}

View File

@@ -0,0 +1,10 @@
package h_mal.appttude.com.firebase
data class SignUpResponse(
val expiresIn: String? = null,
val kind: String? = null,
val idToken: String? = null,
val localId: String? = null,
val email: String? = null,
val refreshToken: String? = null
)

View File

@@ -8,10 +8,4 @@ class HomeRobot: BaseTestRobot() {
fun checkTitleExists(title: String) = matchText(R.id.prova_title_tv, title) fun checkTitleExists(title: String) = matchText(R.id.prova_title_tv, title)
fun clickLogin() = clickButton(R.id.email_sign_in_button)
fun clickRegister() = clickButton(R.id.register_button)
fun clickForgotPassword() = clickButton(R.id.forgot)
} }

View File

@@ -7,7 +7,7 @@ import h_mal.appttude.com.R
fun login(func: LoginRobot.() -> Unit) = LoginRobot().apply { func() } fun login(func: LoginRobot.() -> Unit) = LoginRobot().apply { func() }
class LoginRobot: BaseTestRobot() { class LoginRobot: BaseTestRobot() {
fun setEmail(email: String) = fillEditText(R.id.email, email); fun setEmail(email: String?) = fillEditText(R.id.email, email)
fun setPassword(pass: String) = fillEditText(R.id.password, pass) fun setPassword(pass: String) = fillEditText(R.id.password, pass)

View File

@@ -3,40 +3,31 @@ package h_mal.appttude.com.tests
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest import androidx.test.filters.LargeTest
import androidx.test.rule.ActivityTestRule import h_mal.appttude.com.FirebaseTest
import com.google.firebase.auth.FirebaseAuth
import h_mal.appttude.com.BaseUiTest
import h_mal.appttude.com.R import h_mal.appttude.com.R
import h_mal.appttude.com.USER_PASSWORD
import h_mal.appttude.com.robots.home import h_mal.appttude.com.robots.home
import h_mal.appttude.com.ui.user.LoginActivity
import h_mal.appttude.com.robots.login import h_mal.appttude.com.robots.login
import h_mal.appttude.com.robots.register import h_mal.appttude.com.robots.register
import h_mal.appttude.com.ui.user.LoginActivity
import org.junit.* import org.junit.*
import org.junit.runner.RunWith import org.junit.runner.RunWith
@LargeTest @LargeTest
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class LoginActivityTest: BaseUiTest<LoginActivity>() { class RegisteredUserAuthenticationActivityTest : FirebaseTest<LoginActivity>(LoginActivity::class.java, registered = true, signedIn = false) {
@Ignore
override fun getApplicationClass() = LoginActivity::class.java
@After
fun afterTest(){
FirebaseAuth.getInstance().signOut()
}
@Test @Test
fun verifyUserLogin_validUsernameAndPassword_loggedIn() { fun verifyUserLogin_validUsernameAndPassword_loggedIn() {
login { login {
setEmail("test-user@testuserdriver.com") waitFor(1100)
setPassword("Password1234") setEmail(getEmail())
setPassword(USER_PASSWORD)
clickLogin() clickLogin()
} }
home { home {
checkTitleExists(getResourceString(R.string.welcome_title)) checkTitleExists(getResourceString(R.string.welcome_title))
} }
} }
} }

View File

@@ -0,0 +1,39 @@
package h_mal.appttude.com.tests
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import h_mal.appttude.com.FirebaseTest
import h_mal.appttude.com.R
import h_mal.appttude.com.USER_PASSWORD
import h_mal.appttude.com.robots.home
import h_mal.appttude.com.robots.login
import h_mal.appttude.com.robots.register
import h_mal.appttude.com.ui.user.LoginActivity
import org.junit.*
import org.junit.runner.RunWith
@LargeTest
@RunWith(AndroidJUnit4::class)
class UserAuthenticationActivityTest : FirebaseTest<LoginActivity>(LoginActivity::class.java) {
@Test
fun verifyUserRegistration_validUsernameAndPassword_loggedIn() {
login {
waitFor(1100)
clickRegister()
}
register {
setName("Test User")
setEmail(generateEmailAddress())
setPassword(USER_PASSWORD)
setPasswordConfirm(USER_PASSWORD)
clickLogin()
}
home {
checkTitleExists(getResourceString(R.string.welcome_title))
}
}
}

View File

@@ -0,0 +1,7 @@
<manifest xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<application android:usesCleartextTraffic="true"
tools:ignore="MissingApplicationIcon" />
</manifest>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain>10.0.2.2</domain>
</domain-config>
</network-security-config>

View File

@@ -4,10 +4,7 @@ import android.os.Bundle
import android.view.View import android.view.View
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import h_mal.appttude.com.R import h_mal.appttude.com.R
import h_mal.appttude.com.base.BaseFragment
import h_mal.appttude.com.utils.navigateTo import h_mal.appttude.com.utils.navigateTo
import h_mal.appttude.com.viewmodels.DriverLicenseViewModel
import kotlinx.android.synthetic.main.fragment_driver_overall.* import kotlinx.android.synthetic.main.fragment_driver_overall.*
class DriverOverallFragment : Fragment(R.layout.fragment_driver_overall) { class DriverOverallFragment : Fragment(R.layout.fragment_driver_overall) {

View File

@@ -10,10 +10,8 @@ import h_mal.appttude.com.utils.navigateTo
import h_mal.appttude.com.utils.show import h_mal.appttude.com.utils.show
import h_mal.appttude.com.viewmodels.RoleViewModel import h_mal.appttude.com.viewmodels.RoleViewModel
import kotlinx.android.synthetic.main.driver_profile_request.* import kotlinx.android.synthetic.main.driver_profile_request.*
import kotlinx.android.synthetic.main.fragment_home_driver.* import kotlinx.android.synthetic.main.fragment_home_driver.*
import kotlinx.android.synthetic.main.home_buttons_container.* import kotlinx.android.synthetic.main.home_buttons_container.*
import kotlinx.android.synthetic.main.home_buttons_container.driver
class HomeFragment : DataSubmissionBaseFragment<RoleViewModel, String>(R.layout.fragment_home_driver) { class HomeFragment : DataSubmissionBaseFragment<RoleViewModel, String>(R.layout.fragment_home_driver) {

View File

@@ -4,9 +4,7 @@ import android.os.Bundle
import android.view.View import android.view.View
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import h_mal.appttude.com.R import h_mal.appttude.com.R
import h_mal.appttude.com.base.BaseFragment
import h_mal.appttude.com.utils.navigateTo import h_mal.appttude.com.utils.navigateTo
import h_mal.appttude.com.viewmodels.DriverLicenseViewModel
import kotlinx.android.synthetic.main.fragment_vehicle_overall.* import kotlinx.android.synthetic.main.fragment_vehicle_overall.*

View File

@@ -1,8 +1,8 @@
package h_mal.appttude.com.ui package h_mal.appttude.com.ui
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.View import android.view.View
import androidx.fragment.app.Fragment
import h_mal.appttude.com.R import h_mal.appttude.com.R
import h_mal.appttude.com.utils.navigateTo import h_mal.appttude.com.utils.navigateTo
import kotlinx.android.synthetic.driver.fragment_welcome.* import kotlinx.android.synthetic.driver.fragment_welcome.*

View File

@@ -3,9 +3,9 @@ package h_mal.appttude.com.ui.driverprofile
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import h_mal.appttude.com.dialogs.DateDialog
import h_mal.appttude.com.R import h_mal.appttude.com.R
import h_mal.appttude.com.base.DataSubmissionBaseFragment import h_mal.appttude.com.base.DataSubmissionBaseFragment
import h_mal.appttude.com.dialogs.DateDialog
import h_mal.appttude.com.model.DriverProfileObject import h_mal.appttude.com.model.DriverProfileObject
import h_mal.appttude.com.utils.setGlideImage import h_mal.appttude.com.utils.setGlideImage
import h_mal.appttude.com.viewmodels.DriverProfileViewModel import h_mal.appttude.com.viewmodels.DriverProfileViewModel

View File

@@ -3,9 +3,9 @@ package h_mal.appttude.com.ui.driverprofile
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import h_mal.appttude.com.dialogs.DateDialog
import h_mal.appttude.com.R import h_mal.appttude.com.R
import h_mal.appttude.com.base.DataSubmissionBaseFragment import h_mal.appttude.com.base.DataSubmissionBaseFragment
import h_mal.appttude.com.dialogs.DateDialog
import h_mal.appttude.com.model.PrivateHireObject import h_mal.appttude.com.model.PrivateHireObject
import h_mal.appttude.com.utils.setGlideImage import h_mal.appttude.com.utils.setGlideImage
import h_mal.appttude.com.viewmodels.PrivateHireLicenseViewModel import h_mal.appttude.com.viewmodels.PrivateHireLicenseViewModel

View File

@@ -3,9 +3,9 @@ package h_mal.appttude.com.ui.vehicleprofile
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import h_mal.appttude.com.model.LogbookObject
import h_mal.appttude.com.R import h_mal.appttude.com.R
import h_mal.appttude.com.base.DataSubmissionBaseFragment import h_mal.appttude.com.base.DataSubmissionBaseFragment
import h_mal.appttude.com.model.LogbookObject
import h_mal.appttude.com.utils.setGlideImage import h_mal.appttude.com.utils.setGlideImage
import h_mal.appttude.com.viewmodels.LogbookViewModel import h_mal.appttude.com.viewmodels.LogbookViewModel
import kotlinx.android.synthetic.main.fragment_logbook.* import kotlinx.android.synthetic.main.fragment_logbook.*

View File

@@ -3,10 +3,9 @@ package h_mal.appttude.com.ui.vehicleprofile
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import h_mal.appttude.com.dialogs.DateDialog
import h_mal.appttude.com.R import h_mal.appttude.com.R
import h_mal.appttude.com.base.DataSubmissionBaseFragment import h_mal.appttude.com.base.DataSubmissionBaseFragment
import h_mal.appttude.com.dialogs.DateDialog
import h_mal.appttude.com.model.MotObject import h_mal.appttude.com.model.MotObject
import h_mal.appttude.com.utils.setGlideImage import h_mal.appttude.com.utils.setGlideImage
import h_mal.appttude.com.viewmodels.MotViewModel import h_mal.appttude.com.viewmodels.MotViewModel

View File

@@ -3,11 +3,10 @@ package h_mal.appttude.com.ui.vehicleprofile
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import h_mal.appttude.com.dialogs.DateDialog
import h_mal.appttude.com.model.PrivateHireVehicleObject
import h_mal.appttude.com.R import h_mal.appttude.com.R
import h_mal.appttude.com.base.DataSubmissionBaseFragment import h_mal.appttude.com.base.DataSubmissionBaseFragment
import h_mal.appttude.com.dialogs.DateDialog
import h_mal.appttude.com.model.PrivateHireVehicleObject
import h_mal.appttude.com.utils.setGlideImage import h_mal.appttude.com.utils.setGlideImage
import h_mal.appttude.com.viewmodels.PrivateHireVehicleViewModel import h_mal.appttude.com.viewmodels.PrivateHireVehicleViewModel
import kotlinx.android.synthetic.main.fragment_private_hire_vehicle.* import kotlinx.android.synthetic.main.fragment_private_hire_vehicle.*

View File

@@ -2,10 +2,9 @@ package h_mal.appttude.com.ui.vehicleprofile
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import h_mal.appttude.com.dialogs.DateDialog
import h_mal.appttude.com.R import h_mal.appttude.com.R
import h_mal.appttude.com.base.DataSubmissionBaseFragment import h_mal.appttude.com.base.DataSubmissionBaseFragment
import h_mal.appttude.com.dialogs.DateDialog
import h_mal.appttude.com.model.VehicleProfileObject import h_mal.appttude.com.model.VehicleProfileObject
import h_mal.appttude.com.viewmodels.VehicleProfileViewModel import h_mal.appttude.com.viewmodels.VehicleProfileViewModel
import kotlinx.android.synthetic.main.fragment_vehicle_setup.* import kotlinx.android.synthetic.main.fragment_vehicle_setup.*

View File

@@ -6,11 +6,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ListView import android.widget.ListView
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.google.firebase.database.DataSnapshot
import com.google.firebase.database.DatabaseError
import com.google.firebase.database.DatabaseReference import com.google.firebase.database.DatabaseReference
import com.google.firebase.database.ValueEventListener
import h_mal.appttude.com.R import h_mal.appttude.com.R
class ArchiveFragment : Fragment() { class ArchiveFragment : Fragment() {

View File

@@ -1,19 +1,13 @@
package h_mal.appttude.com.Archive package h_mal.appttude.com.Archive
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
//import h_mal.appttude.com.Global.FirebaseClass //import h_mal.appttude.com.Global.FirebaseClass
//import h_mal.appttude.com.Global.ImageSwiperClass //import h_mal.appttude.com.Global.ImageSwiperClass
//import h_mal.appttude.com.Objects.ArchiveObject //import h_mal.appttude.com.Objects.ArchiveObject
import h_mal.appttude.com.model.InsuranceObject import android.content.Context
import h_mal.appttude.com.R import android.view.View
import h_mal.appttude.com.model.VehicleProfileObject import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.TextView
import h_mal.appttude.com.utils.DateUtils.convertDateStringDatePattern import h_mal.appttude.com.utils.DateUtils.convertDateStringDatePattern
import java.text.ParseException import java.text.ParseException

View File

@@ -4,7 +4,6 @@ import android.app.Application
import h_mal.appttude.com.data.FirebaseAuthSource import h_mal.appttude.com.data.FirebaseAuthSource
import h_mal.appttude.com.data.FirebaseDatabaseSource import h_mal.appttude.com.data.FirebaseDatabaseSource
import h_mal.appttude.com.data.FirebaseStorageSource import h_mal.appttude.com.data.FirebaseStorageSource
import h_mal.appttude.com.espresso.IdlingResourceClass
import org.kodein.di.Kodein import org.kodein.di.Kodein
import org.kodein.di.KodeinAware import org.kodein.di.KodeinAware
import org.kodein.di.android.x.androidXModule import org.kodein.di.android.x.androidXModule

View File

@@ -4,27 +4,25 @@ import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.view.ViewGroup.LayoutParams import android.view.ViewGroup.LayoutParams
import android.view.ViewGroup.LayoutParams.* import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.annotation.VisibleForTesting
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import h_mal.appttude.com.application.ApplicationViewModelFactory import androidx.test.espresso.IdlingResource
import h_mal.appttude.com.R import h_mal.appttude.com.R
import h_mal.appttude.com.application.ApplicationViewModelFactory
import h_mal.appttude.com.data.ViewState import h_mal.appttude.com.data.ViewState
import h_mal.appttude.com.espresso.IdlingResourceClass import h_mal.appttude.com.utils.*
import h_mal.appttude.com.utils.displayToast
import h_mal.appttude.com.utils.hide
import h_mal.appttude.com.utils.show
import h_mal.appttude.com.utils.triggerAnimation
import org.kodein.di.KodeinAware import org.kodein.di.KodeinAware
import org.kodein.di.android.kodein import org.kodein.di.android.kodein
import org.kodein.di.generic.instance import org.kodein.di.generic.instance
abstract class BaseActivity<V : BaseViewModel> : AppCompatActivity(), KodeinAware { abstract class BaseActivity<V : BaseViewModel> : AppCompatActivity(), KodeinAware {
// The Idling Resource which will be null in production.
private var mIdlingResource: BasicIdlingResource? = null
private lateinit var loadingView: View private lateinit var loadingView: View
abstract fun getViewModel(): V? abstract fun getViewModel(): V?
@@ -32,7 +30,6 @@ abstract class BaseActivity<V : BaseViewModel> : AppCompatActivity(), KodeinAwar
override val kodein by kodein() override val kodein by kodein()
val factory by instance<ApplicationViewModelFactory>() val factory by instance<ApplicationViewModelFactory>()
private val idlingResource by instance<IdlingResourceClass>()
inline fun <reified VM : ViewModel> createLazyViewModel(): Lazy<VM> = viewModels { factory } inline fun <reified VM : ViewModel> createLazyViewModel(): Lazy<VM> = viewModels { factory }
inline fun <reified VM : ViewModel> createViewModel(): VM = inline fun <reified VM : ViewModel> createViewModel(): VM =
@@ -54,6 +51,7 @@ abstract class BaseActivity<V : BaseViewModel> : AppCompatActivity(), KodeinAwar
* loading * loading
*/ */
private fun instantiateLoadingView(){ private fun instantiateLoadingView(){
// loadingView = View.inflate(this, R.layout.progress_layout, null)
loadingView = layoutInflater.inflate(R.layout.progress_layout, null) loadingView = layoutInflater.inflate(R.layout.progress_layout, null)
loadingView.setOnClickListener(null) loadingView.setOnClickListener(null)
addContentView(loadingView, LayoutParams(MATCH_PARENT, MATCH_PARENT)) addContentView(loadingView, LayoutParams(MATCH_PARENT, MATCH_PARENT))
@@ -76,7 +74,7 @@ abstract class BaseActivity<V : BaseViewModel> : AppCompatActivity(), KodeinAwar
open fun onStarted() { open fun onStarted() {
loadingView.fadeIn() loadingView.fadeIn()
loading = true loading = true
IdlingResourceClass.increment() mIdlingResource?.setIdleState(false)
} }
/** /**
@@ -85,7 +83,7 @@ abstract class BaseActivity<V : BaseViewModel> : AppCompatActivity(), KodeinAwar
open fun onSuccess(data: Any?) { open fun onSuccess(data: Any?) {
loadingView.fadeOut() loadingView.fadeOut()
loading = false loading = false
IdlingResourceClass.decrement() mIdlingResource?.setIdleState(true)
} }
/** /**
@@ -95,17 +93,17 @@ abstract class BaseActivity<V : BaseViewModel> : AppCompatActivity(), KodeinAwar
error?.let { displayToast(it) } error?.let { displayToast(it) }
loadingView.fadeOut() loadingView.fadeOut()
loading = false loading = false
IdlingResourceClass.decrement() mIdlingResource?.setIdleState(true)
} }
private fun configureObserver() { private fun configureObserver() {
getViewModel()?.uiState?.observe(this, Observer { getViewModel()?.uiState?.observe(this) {
when (it) { when (it) {
is ViewState.HasStarted -> onStarted() is ViewState.HasStarted -> onStarted()
is ViewState.HasData<*> -> onSuccess(it.data.getContentIfNotHandled()) is ViewState.HasData<*> -> onSuccess(it.data.getContentIfNotHandled())
is ViewState.HasError -> onFailure(it.error.getContentIfNotHandled()) is ViewState.HasError -> onFailure(it.error.getContentIfNotHandled())
} }
}) }
} }
private fun View.fadeIn() = apply { private fun View.fadeIn() = apply {
@@ -123,4 +121,14 @@ abstract class BaseActivity<V : BaseViewModel> : AppCompatActivity(), KodeinAwar
if (!loading) super.onBackPressed() if (!loading) super.onBackPressed()
} }
/**
* Only called from test, creates and returns a new [BasicIdlingResource].
*/
@VisibleForTesting
fun getIdlingResource(): IdlingResource? {
if (mIdlingResource == null) {
mIdlingResource = BasicIdlingResource()
}
return mIdlingResource
}
} }

View File

@@ -1,10 +1,12 @@
package h_mal.appttude.com.base package h_mal.appttude.com.base
import android.net.Uri import android.net.Uri
import androidx.lifecycle.MutableLiveData
import com.google.firebase.database.DatabaseReference import com.google.firebase.database.DatabaseReference
import com.google.firebase.storage.StorageReference import com.google.firebase.storage.StorageReference
import h_mal.appttude.com.data.* import h_mal.appttude.com.data.FirebaseAuthentication
import h_mal.appttude.com.data.FirebaseCompletion
import h_mal.appttude.com.data.FirebaseDatabaseSource
import h_mal.appttude.com.data.FirebaseStorageSource
import h_mal.appttude.com.utils.Coroutines.io import h_mal.appttude.com.utils.Coroutines.io
import h_mal.appttude.com.utils.DateUtils.getDateTimeStamp import h_mal.appttude.com.utils.DateUtils.getDateTimeStamp
import h_mal.appttude.com.utils.getDataFromDatabaseRef import h_mal.appttude.com.utils.getDataFromDatabaseRef

View File

@@ -28,7 +28,7 @@ class FirebaseAuthSource: FirebaseAuthentication{
): Task<Void> { ): Task<Void> {
val profileUpdates = UserProfileChangeRequest.Builder().apply { val profileUpdates = UserProfileChangeRequest.Builder().apply {
name?.let { setDisplayName(it) } name?.let { setDisplayName(it) }
profilePic?.let { setPhotoUri(it) } profilePic?.let { photoUri = it }
}.build() }.build()
return getCurrentUser().updateProfile(profileUpdates) return getCurrentUser().updateProfile(profileUpdates)
} }

View File

@@ -2,7 +2,6 @@ package h_mal.appttude.com.data
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import com.google.firebase.auth.FirebaseAuth import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.FirebaseUser
class FirebaseLiveData( class FirebaseLiveData(
private val firebaseAuth: FirebaseAuth private val firebaseAuth: FirebaseAuth

View File

@@ -1,7 +1,6 @@
package h_mal.appttude.com.data package h_mal.appttude.com.data
import com.google.firebase.auth.FirebaseUser import com.google.firebase.auth.FirebaseUser
import h_mal.appttude.com.utils.Event
sealed class UserAuthState { sealed class UserAuthState {
object LoggedOut : UserAuthState() object LoggedOut : UserAuthState()

View File

@@ -5,16 +5,13 @@ import android.app.AlertDialog
import android.app.DatePickerDialog import android.app.DatePickerDialog
import android.app.DatePickerDialog.OnDateSetListener import android.app.DatePickerDialog.OnDateSetListener
import android.icu.util.Calendar import android.icu.util.Calendar
import android.os.Build
import android.view.View
import android.widget.EditText import android.widget.EditText
import androidx.annotation.RequiresApi
import h_mal.appttude.com.R import h_mal.appttude.com.R
import h_mal.appttude.com.utils.DateUtils import h_mal.appttude.com.utils.DateUtils
private const val DATE_FORMAT = "dd/MM/yyyy" private const val DATE_FORMAT = "dd/MM/yyyy"
@RequiresApi(api = Build.VERSION_CODES.N) @Suppress("DEPRECATION")
class DateDialog( class DateDialog(
private val editText: EditText, private val editText: EditText,
dateSelected:(String?) -> Unit dateSelected:(String?) -> Unit

View File

@@ -1,24 +0,0 @@
package h_mal.appttude.com.espresso
import androidx.test.espresso.idling.CountingIdlingResource
object IdlingResourceClass {
private val CLASS_NAME = "IdlingResourceClass"
private const val RESOURCE = "GLOBAL"
@JvmField val countingIdlingResource = CountingIdlingResource(RESOURCE)
fun increment() {
if (!countingIdlingResource.isIdleNow) {
countingIdlingResource.increment()
}
}
fun decrement() {
if (countingIdlingResource.isIdleNow) {
countingIdlingResource.decrement()
}
}
}

View File

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

View File

@@ -5,9 +5,9 @@ import android.content.Intent
import android.os.Bundle import android.os.Bundle
import com.google.firebase.auth.AuthResult import com.google.firebase.auth.AuthResult
import com.google.firebase.auth.FirebaseUser import com.google.firebase.auth.FirebaseUser
import h_mal.appttude.com.ui.MainActivity
import h_mal.appttude.com.R import h_mal.appttude.com.R
import h_mal.appttude.com.base.BaseActivity import h_mal.appttude.com.base.BaseActivity
import h_mal.appttude.com.ui.MainActivity
import h_mal.appttude.com.viewmodels.UserViewModel import h_mal.appttude.com.viewmodels.UserViewModel

View File

@@ -0,0 +1,32 @@
package h_mal.appttude.com.utils
import androidx.test.espresso.IdlingResource
import androidx.test.espresso.IdlingResource.ResourceCallback
import java.util.concurrent.atomic.AtomicBoolean
class BasicIdlingResource : IdlingResource {
private lateinit var mCallback: ResourceCallback
// Idleness is controlled with this boolean.
private val mIsIdleNow: AtomicBoolean = AtomicBoolean(true)
override fun getName(): String = this.javaClass.name
override fun isIdleNow(): Boolean = mIsIdleNow.get()
override fun registerIdleTransitionCallback(callback: ResourceCallback) {
mCallback = callback
}
/**
* Sets the new idle state, if isIdleNow is true, it pings the [ResourceCallback].
* @param isIdleNow false if there are pending operations, true if idle.
*/
fun setIdleState(isIdleNow: Boolean) {
mIsIdleNow.set(isIdleNow)
if (isIdleNow) {
mCallback.onTransitionToIdle()
}
}
}

View File

@@ -3,8 +3,7 @@ package h_mal.appttude.com.utils
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.content.pm.PackageManager.*
import android.net.Uri import android.net.Uri
import android.provider.Settings import android.provider.Settings
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog

View File

@@ -1,5 +1,6 @@
package h_mal.appttude.com.utils package h_mal.appttude.com.utils
import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
@@ -20,13 +21,9 @@ import androidx.annotation.DrawableRes
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.squareup.picasso.Picasso import com.squareup.picasso.Picasso
import com.squareup.picasso.Target import com.squareup.picasso.Target
import h_mal.appttude.com.R import h_mal.appttude.com.R
import com.bumptech.glide.request.target.Target as GlideRequestTarget
fun View.show() { fun View.show() {
this.visibility = View.VISIBLE this.visibility = View.VISIBLE
@@ -54,6 +51,7 @@ fun EditText.setEnterPressedListener(action: () -> Unit) {
}) })
} }
@SuppressLint("CheckResult")
fun ImageView.setGlideImage( fun ImageView.setGlideImage(
url: String?, url: String?,
@DrawableRes placeholderRes: Int = R.drawable.choice_img_round @DrawableRes placeholderRes: Int = R.drawable.choice_img_round
@@ -70,6 +68,7 @@ fun ImageView.setGlideImage(
.into(this) .into(this)
} }
@SuppressLint("CheckResult")
fun ImageView.setGlideImage( fun ImageView.setGlideImage(
url: Uri?, url: Uri?,
@DrawableRes placeholderRes: Int = R.drawable.choice_img_round @DrawableRes placeholderRes: Int = R.drawable.choice_img_round

View File

@@ -3,11 +3,11 @@ package h_mal.appttude.com.viewmodels
import android.net.Uri import android.net.Uri
import com.google.firebase.database.DatabaseReference import com.google.firebase.database.DatabaseReference
import com.google.firebase.storage.StorageReference import com.google.firebase.storage.StorageReference
import h_mal.appttude.com.model.InsuranceObject
import h_mal.appttude.com.base.DataSubmissionBaseViewModel import h_mal.appttude.com.base.DataSubmissionBaseViewModel
import h_mal.appttude.com.data.FirebaseAuthentication import h_mal.appttude.com.data.FirebaseAuthentication
import h_mal.appttude.com.data.FirebaseDatabaseSource import h_mal.appttude.com.data.FirebaseDatabaseSource
import h_mal.appttude.com.data.FirebaseStorageSource import h_mal.appttude.com.data.FirebaseStorageSource
import h_mal.appttude.com.model.InsuranceObject
import h_mal.appttude.com.utils.Coroutines.io import h_mal.appttude.com.utils.Coroutines.io
class InsuranceViewModel ( class InsuranceViewModel (
@@ -17,7 +17,7 @@ class InsuranceViewModel (
) : DataSubmissionBaseViewModel<InsuranceObject>(auth, database, storage) { ) : DataSubmissionBaseViewModel<InsuranceObject>(auth, database, storage) {
override val databaseRef: DatabaseReference = database.getInsuranceDetailsRef(uid) override val databaseRef: DatabaseReference = database.getInsuranceDetailsRef(uid)
override val storageRef: StorageReference? = storage.insuranceStorageRef(uid) override val storageRef: StorageReference = storage.insuranceStorageRef(uid)
override val objectName: String = "insurance" override val objectName: String = "insurance"
override fun getDataFromDatabase() = getDataClass<InsuranceObject>() override fun getDataFromDatabase() = getDataClass<InsuranceObject>()

View File

@@ -3,11 +3,11 @@ package h_mal.appttude.com.viewmodels
import android.net.Uri import android.net.Uri
import com.google.firebase.database.DatabaseReference import com.google.firebase.database.DatabaseReference
import com.google.firebase.storage.StorageReference import com.google.firebase.storage.StorageReference
import h_mal.appttude.com.model.LogbookObject
import h_mal.appttude.com.base.DataSubmissionBaseViewModel import h_mal.appttude.com.base.DataSubmissionBaseViewModel
import h_mal.appttude.com.data.FirebaseAuthentication import h_mal.appttude.com.data.FirebaseAuthentication
import h_mal.appttude.com.data.FirebaseDatabaseSource import h_mal.appttude.com.data.FirebaseDatabaseSource
import h_mal.appttude.com.data.FirebaseStorageSource import h_mal.appttude.com.data.FirebaseStorageSource
import h_mal.appttude.com.model.LogbookObject
import h_mal.appttude.com.utils.Coroutines.io import h_mal.appttude.com.utils.Coroutines.io
class LogbookViewModel ( class LogbookViewModel (

View File

@@ -3,11 +3,11 @@ package h_mal.appttude.com.viewmodels
import android.net.Uri import android.net.Uri
import com.google.firebase.database.DatabaseReference import com.google.firebase.database.DatabaseReference
import com.google.firebase.storage.StorageReference import com.google.firebase.storage.StorageReference
import h_mal.appttude.com.model.PrivateHireVehicleObject
import h_mal.appttude.com.base.DataSubmissionBaseViewModel import h_mal.appttude.com.base.DataSubmissionBaseViewModel
import h_mal.appttude.com.data.FirebaseAuthentication import h_mal.appttude.com.data.FirebaseAuthentication
import h_mal.appttude.com.data.FirebaseDatabaseSource import h_mal.appttude.com.data.FirebaseDatabaseSource
import h_mal.appttude.com.data.FirebaseStorageSource import h_mal.appttude.com.data.FirebaseStorageSource
import h_mal.appttude.com.model.PrivateHireVehicleObject
import h_mal.appttude.com.utils.Coroutines.io import h_mal.appttude.com.utils.Coroutines.io
class PrivateHireVehicleViewModel ( class PrivateHireVehicleViewModel (
@@ -17,7 +17,7 @@ class PrivateHireVehicleViewModel (
) : DataSubmissionBaseViewModel<PrivateHireVehicleObject>(auth, database, storage) { ) : DataSubmissionBaseViewModel<PrivateHireVehicleObject>(auth, database, storage) {
override val databaseRef: DatabaseReference = database.getPrivateHireVehicleRef(uid) override val databaseRef: DatabaseReference = database.getPrivateHireVehicleRef(uid)
override val storageRef: StorageReference? = storage.privateHireVehicleStorageRef(uid) override val storageRef: StorageReference = storage.privateHireVehicleStorageRef(uid)
override val objectName: String = "private hire vehicle license" override val objectName: String = "private hire vehicle license"
override fun getDataFromDatabase() = getDataClass<PrivateHireVehicleObject>() override fun getDataFromDatabase() = getDataClass<PrivateHireVehicleObject>()

View File

@@ -7,8 +7,6 @@ import h_mal.appttude.com.data.FirebaseCompletion
import h_mal.appttude.com.data.FirebaseStorageSource import h_mal.appttude.com.data.FirebaseStorageSource
import h_mal.appttude.com.utils.Coroutines.io import h_mal.appttude.com.utils.Coroutines.io
import kotlinx.coroutines.tasks.await import kotlinx.coroutines.tasks.await
import java.io.IOException
import java.lang.Exception
class UpdateUserViewModel( class UpdateUserViewModel(
private val auth: FirebaseAuthentication, private val auth: FirebaseAuthentication,

View File

@@ -7,8 +7,6 @@ import h_mal.appttude.com.data.FirebaseCompletion
import h_mal.appttude.com.utils.Coroutines.io import h_mal.appttude.com.utils.Coroutines.io
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.tasks.await import kotlinx.coroutines.tasks.await
import java.io.IOException
import java.lang.Exception
class UserViewModel( class UserViewModel(
val auth: FirebaseAuthentication val auth: FirebaseAuthentication

View File

@@ -1 +0,0 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"></resources>

View File

@@ -9,7 +9,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:4.1.3' classpath 'com.android.tools.build:gradle:7.2.2'
classpath 'com.google.gms:google-services:4.3.15' classpath 'com.google.gms:google-services:4.3.15'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10"

10
database.rules.json Normal file
View File

@@ -0,0 +1,10 @@
{
"rules": {
"user": {
".read": true,
"$user_id": {
".write": "$user_id === auth.uid"
}
}
}
}

23
firebase.json Normal file
View File

@@ -0,0 +1,23 @@
{
"emulators": {
"auth": {
"port": 9099
},
"database": {
"port": 9000
},
"storage": {
"port": 9199
},
"ui": {
"enabled": true
},
"singleProjectMode": true
},
"database": {
"rules": "database.rules.json"
},
"storage": {
"rules": "storage.rules"
}
}

8
storage.rules Normal file
View File

@@ -0,0 +1,8 @@
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if false;
}
}
}