- refactoring of admin app

- file structure updated

Took 34 hours 38 minutes
This commit is contained in:
2023-05-06 23:59:13 +01:00
parent 0c09966002
commit 2677b3ae25
80 changed files with 1476 additions and 828 deletions

View File

@@ -5,7 +5,7 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:name="h_mal.appttude.com.driver.application.DriverApplication"
android:name=".application.DriverApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
@@ -13,8 +13,7 @@
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name="h_mal.appttude.com.driver.ui.user.LoginActivity"
android:label="@string/app_name"
android:name=".ui.user.LoginActivity"
android:theme="@style/AppTheme.NoActionBar.User"
android:exported="true">
<intent-filter>
@@ -25,17 +24,16 @@
</intent-filter>
</activity>
<activity
android:name="h_mal.appttude.com.driver.ui.MainActivity"
android:name=".ui.MainActivity"
android:configChanges="orientation|screenSize"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar" />
<activity
android:name="h_mal.appttude.com.driver.ui.update.UpdateActivity"
android:name=".ui.update.UpdateActivity"
android:theme="@style/AppTheme.NoActionBar.Update" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="h_mal.appttude.com.driver"
android:authorities="${applicationId}.contentprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data

View File

@@ -1,72 +0,0 @@
package h_mal.appttude.com.driver.application
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import h_mal.appttude.com.driver.data.FirebaseAuthSource
import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
import h_mal.appttude.com.driver.data.FirebaseStorageSource
import h_mal.appttude.com.driver.viewmodels.*
class ApplicationViewModelFactory(
private val auth: FirebaseAuthSource,
private val database: FirebaseDatabaseSource,
private val storage: FirebaseStorageSource
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
with(modelClass) {
return when {
isAssignableFrom(UserViewModel::class.java) -> UserViewModel(auth)
isAssignableFrom(MainViewModel::class.java) -> MainViewModel(auth, database)
isAssignableFrom(UpdateUserViewModel::class.java) -> UpdateUserViewModel(
auth,
storage
)
isAssignableFrom(DriverLicenseViewModel::class.java) -> DriverLicenseViewModel(
auth,
database,
storage
)
isAssignableFrom(DriverProfileViewModel::class.java) -> DriverProfileViewModel(
auth,
database,
storage
)
isAssignableFrom(PrivateHireLicenseViewModel::class.java) -> PrivateHireLicenseViewModel(
auth,
database,
storage
)
isAssignableFrom(VehicleProfileViewModel::class.java) -> VehicleProfileViewModel(
auth,
database,
storage
)
isAssignableFrom(InsuranceViewModel::class.java) -> InsuranceViewModel(
auth,
database,
storage
)
isAssignableFrom(MotViewModel::class.java) -> MotViewModel(auth, database, storage)
isAssignableFrom(LogbookViewModel::class.java) -> LogbookViewModel(
auth,
database,
storage
)
isAssignableFrom(PrivateHireVehicleViewModel::class.java) -> PrivateHireVehicleViewModel(
auth,
database,
storage
)
isAssignableFrom(RoleViewModel::class.java) -> RoleViewModel(
auth,
database,
storage
)
else -> throw IllegalArgumentException("Unknown ViewModel class")
} as T
}
}
}

View File

@@ -4,6 +4,7 @@ import android.app.Application
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
@@ -20,6 +21,7 @@ class DriverApplication : Application(), KodeinAware {
bind() from singleton { FirebaseAuthSource() }
bind() from singleton { FirebaseDatabaseSource() }
bind() from singleton { FirebaseStorageSource() }
bind() from provider { ApplicationViewModelFactory(instance(), instance(), instance()) }
bind() from singleton { PreferenceProvider(this@DriverApplication) }
bind() from provider { ApplicationViewModelFactory(instance(), instance(), instance(), instance()) }
}
}

View File

@@ -2,7 +2,6 @@ package h_mal.appttude.com.driver.base
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup.LayoutParams
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
@@ -16,12 +15,11 @@ import h_mal.appttude.com.driver.R
import h_mal.appttude.com.driver.application.ApplicationViewModelFactory
import h_mal.appttude.com.driver.data.ViewState
import h_mal.appttude.com.driver.utils.*
import h_mal.appttude.com.driver.utils.GenericsHelper.getGenericClassAt
import h_mal.appttude.com.driver.utils.GenericsHelper.inflateBindingByType
import org.kodein.di.KodeinAware
import org.kodein.di.android.kodein
import org.kodein.di.generic.instance
import java.lang.reflect.ParameterizedType
import kotlin.reflect.KClass
abstract class BaseActivity<V : BaseViewModel, VB : ViewBinding> : AppCompatActivity(), KodeinAware {
// The Idling Resource which will be null in production.
@@ -47,34 +45,12 @@ abstract class BaseActivity<V : BaseViewModel, VB : ViewBinding> : AppCompatActi
{ defaultViewModelCreationExtras }
)
@Suppress("UNCHECKED_CAST")
fun <CLASS : Any> Any.getGenericClassAt(position: Int): KClass<CLASS> =
((javaClass.genericSuperclass as? ParameterizedType)
?.actualTypeArguments?.getOrNull(position) as? Class<CLASS>)
?.kotlin
?: throw IllegalStateException("Can not find class from generic argument")
/**
* Create a view binding out of the the generic [VB]
*/
private fun inflateBindingByType(
genericClassAt: KClass<VB>
): VB = try {
@Suppress("UNCHECKED_CAST")
genericClassAt.java.methods.first { viewBinding ->
viewBinding.parameterTypes.size == 1
&& viewBinding.parameterTypes.getOrNull(0) == LayoutInflater::class.java
}.invoke(null, layoutInflater) as VB
} catch (exception: Exception) {
throw IllegalStateException("Can not inflate binding from generic")
}
private var loading: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
configureObserver()
_binding = inflateBindingByType(getGenericClassAt(1))
_binding = inflateBindingByType(getGenericClassAt(1), layoutInflater)
setContentView(requireNotNull(_binding).root)
setupView(binding)
}

View File

@@ -0,0 +1,55 @@
package h_mal.appttude.com.driver.base
import android.net.ConnectivityManager
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import androidx.viewbinding.ViewBinding
import com.firebase.ui.database.FirebaseRecyclerAdapter
import com.firebase.ui.database.FirebaseRecyclerOptions
import h_mal.appttude.com.driver.utils.GenericsHelper.getGenericClassAt
import h_mal.appttude.com.driver.utils.GenericsHelper.inflateBindingByType
import java.nio.ByteBuffer
open class BaseFirebaseAdapter<T: Any, VB : ViewBinding>(options: FirebaseRecyclerOptions<T>, private val layoutInflater: LayoutInflater):
FirebaseRecyclerAdapter<T, CustomViewHolder<VB>>(options) {
private val connectivityManager = layoutInflater.context.getSystemService(ConnectivityManager::class.java) as ConnectivityManager
private var _binding: VB? = null
val binding: VB
get() = _binding ?: error("Must only access binding while fragment is attached.")
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder<VB> {
_binding = inflateBindingByType(getGenericClassAt(1), layoutInflater)
val lp = RecyclerView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
binding.root.layoutParams = lp
return CustomViewHolder(requireNotNull(_binding))
}
override fun onBindViewHolder(holder: CustomViewHolder<VB>, position: Int, model: T) { }
override fun getItemId(position: Int): Long {
return snapshots.getSnapshot(position).key?.toByteArray()
?.let { ByteBuffer.wrap(it).long } ?: super.getItemId(position)
}
fun getKeyAtPosition(position: Int) = snapshots.getSnapshot(position).key
override fun startListening() {
super.startListening()
// check if network is connected
if (connectivityManager.activeNetwork == null) {
connectionLost()
}
}
open fun connectionLost() {}
}
class CustomViewHolder<VB : ViewBinding>(val viewBinding: VB): ViewHolder(viewBinding.root)

View File

@@ -1,29 +1,27 @@
package h_mal.appttude.com.driver.base
import android.app.Activity
import android.content.ClipData
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContract
import androidx.fragment.app.Fragment
import androidx.fragment.app.createViewModelLazy
import androidx.viewbinding.ViewBinding
import h_mal.appttude.com.driver.application.ApplicationViewModelFactory
import h_mal.appttude.com.driver.data.ViewState
import h_mal.appttude.com.driver.utils.GenericsHelper.getGenericClassAt
import h_mal.appttude.com.driver.utils.GenericsHelper.inflateBindingByType
import h_mal.appttude.com.driver.utils.PermissionsUtils
import org.kodein.di.KodeinAware
import org.kodein.di.android.x.kodein
import org.kodein.di.generic.instance
import java.lang.reflect.ParameterizedType
import kotlin.reflect.KClass
const val IMAGE_SELECT_REQUEST_CODE = 401
abstract class BaseFragment<V : BaseViewModel, VB : ViewBinding>(
) : Fragment(), KodeinAware {
abstract class BaseFragment<V : BaseViewModel, VB : ViewBinding> : Fragment(), KodeinAware {
private var _binding: VB? = null
private val binding: VB
@@ -31,7 +29,12 @@ abstract class BaseFragment<V : BaseViewModel, VB : ViewBinding>(
var mActivity: BaseActivity<V, *>? = null
override val kodein by kodein()
private val factory by instance<ApplicationViewModelFactory>()
val viewModel: V by getFragmentViewModel()
private fun getFragmentViewModel(): Lazy<V> =
createViewModelLazy(getGenericClassAt(0), { viewModelStore }, factoryProducer = { factory })
private var multipleImage: Boolean = false
@@ -39,33 +42,6 @@ abstract class BaseFragment<V : BaseViewModel, VB : ViewBinding>(
multipleImage = true
}
override val kodein by kodein()
val factory by instance<ApplicationViewModelFactory>()
fun getFragmentViewModel(): Lazy<V> =
createViewModelLazy(getGenericClassAt(0), { viewModelStore }, factoryProducer = { factory })
fun LayoutInflater.inflateBindingByType(
container: ViewGroup?,
genericClassAt: KClass<VB>
): VB = try {
@Suppress("UNCHECKED_CAST")
genericClassAt.java.methods.first { inflateFun ->
inflateFun.parameterTypes.size == 3
&& inflateFun.parameterTypes.getOrNull(0) == LayoutInflater::class.java
&& inflateFun.parameterTypes.getOrNull(1) == ViewGroup::class.java
&& inflateFun.parameterTypes.getOrNull(2) == Boolean::class.java
}.invoke(null, this, container, false) as VB
} catch (exception: Exception) {
throw IllegalStateException("Can not inflate binding from generic")
}
@Suppress("UNCHECKED_CAST")
fun <CLASS : Any> Any.getGenericClassAt(position: Int): KClass<CLASS> =
((javaClass.genericSuperclass as? ParameterizedType)
?.actualTypeArguments?.getOrNull(position) as? Class<CLASS>)
?.kotlin
?: throw IllegalStateException("Can not find class from generic argument")
override fun onCreateView(
inflater: LayoutInflater,
@@ -126,25 +102,6 @@ abstract class BaseFragment<V : BaseViewModel, VB : ViewBinding>(
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK) {
when (requestCode) {
IMAGE_SELECT_REQUEST_CODE -> {
data?.clipData?.convertToList()?.let { clip ->
val list = clip.takeIf { it.size > 10 }?.let {
clip.subList(0, 9)
} ?: clip
onImageGalleryResult(list)
return
}
onImageGalleryResult(data?.data)
}
}
}
}
private fun ClipData.convertToList(): List<Uri> = 0.rangeTo(itemCount).map { getItemAt(it).uri }
/**
@@ -180,10 +137,33 @@ abstract class BaseFragment<V : BaseViewModel, VB : ViewBinding>(
open fun onImageGalleryResult(imageUris: List<Uri>?) {}
fun openGalleryForImage() {
val intent = Intent(Intent.ACTION_PICK)
intent.type = "image/*"
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, multipleImage)
startActivityForResult(intent, IMAGE_SELECT_REQUEST_CODE)
registerForActivityResult(getResultsContract()) { result ->
@Suppress("UNCHECKED_CAST")
when (result) {
is Uri -> onImageGalleryResult(result)
is List<*> -> onImageGalleryResult(result as List<Uri>)
}
}.launch(multipleImage)
}
private fun getResultsContract(): ActivityResultContract<Boolean, Any?> {
return object : ActivityResultContract<Boolean, Any?>() {
override fun createIntent(context: Context, input: Boolean): Intent {
return Intent(Intent.ACTION_PICK).apply {
type = "image/*"
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, input)
}
}
override fun parseResult(resultCode: Int, intent: Intent?): Any? {
intent?.clipData?.convertToList()?.let { clip ->
val list = clip.takeIf { it.size > 10 }?.let {
clip.subList(0, 9)
} ?: clip
return list
}
return intent?.data
}
}
}
}

View File

@@ -29,14 +29,11 @@ abstract class BaseViewModel : ViewModel() {
operation()
} catch (e: Exception) {
e.printStackTrace()
e.message?.let {
onError(it)
return
}
defaultErrorMessage?.let {
onError(it)
return
}
onError((e.message ?: "Operation failed!!"))
}
}
}

View File

@@ -15,6 +15,7 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import java.io.IOException
abstract class DataSubmissionBaseViewModel<T : Any>(
auth: FirebaseAuthentication,
private val database: FirebaseDatabaseSource,
@@ -32,7 +33,7 @@ abstract class DataSubmissionBaseViewModel<T : Any>(
open fun setDataInDatabase(data: T, localImageUris: List<Uri?>?): Job = Job()
open fun setDataInDatabase(data: T) {}
inline fun <reified T : Any> getDataClass() = io {
inline fun <reified T : Any> retrieveDataFromDatabase() = io {
doTryOperation("Failed to retrieve $objectName") {
val data = databaseRef.getDataFromDatabaseRef<T>()
onSuccess(data ?: FirebaseCompletion.Default)

View File

@@ -21,6 +21,7 @@ const val PRIVATE_HIRE_VEHICLE = "private_hire_vehicle"
const val VEHICLE_DETAILS = "vehicle_details"
const val ARCHIVE = "archive"
@SuppressWarnings("unused|WeakerAccess")
class FirebaseDatabaseSource {
private val database = FirebaseDatabase.getInstance()
@@ -35,7 +36,12 @@ class FirebaseDatabaseSource {
return data
}
fun getUserRef(uid: String) = database.getReference(USER_CONST).child(uid)
fun getDatabaseReferenceFromLink(link: String) = database.getReferenceFromUrl(link)
val users = database.getReference(USER_CONST)
fun getUsersRef() = database.reference.child(USER_CONST)
fun getUserRef(uid: String) = users.child(uid)
fun getUserDetailsRef(uid: String) = getUserRef(uid).child(USER_DETAILS)
fun getVehicleRef(uid: String) = getUserRef(uid).child(VEHICLE_PROFILE)
fun getDriverRef(uid: String) = getUserRef(uid).child(DRIVER_PROFILE)

View File

@@ -0,0 +1,29 @@
package h_mal.appttude.com.driver.data.prefs
import android.content.Context
import android.content.SharedPreferences
import androidx.preference.PreferenceManager
/**
* Shared prefs class used for storing conversion name values as pairs
* Then retrieving as pairs
*
*/
const val SORT_OPTION = "SORT_OPTION"
class PreferenceProvider (context: Context) {
private val appContext = context.applicationContext
private val preference: SharedPreferences =
PreferenceManager.getDefaultSharedPreferences(appContext)
fun setSortOption(sortLabel: String) {
preference.edit()
.putString(SORT_OPTION, sortLabel)
.apply()
}
fun getSortOption(): String? = preference
.getString(SORT_OPTION, null)
}

View File

@@ -1,13 +1,22 @@
package h_mal.appttude.com.driver.utils
/**
* Extension function that will execute high order if value is true or do nothing
*
* @sample #boolean.isTrue{ #Do something when its true }
*/
inline fun Boolean.isTrue(block: () -> Unit){
if (this) {
block()
}
}
inline fun <T, R> T.isNotNull(block: (T) -> R): R?{
/**
* Extension function that will execute high order if value is not null or do nothing
*
* @sample #nullable.isNotNull{i -> i.doSomethingSinceItsNotNull() }
*/
inline fun <T, R> T?.isNotNull(block: (T) -> R): R?{
return if (this != null) {
block(this)
} else {

View File

@@ -42,4 +42,15 @@ suspend inline fun <reified T : Any> DatabaseReference.getDataFromDatabaseRef():
throw response.error.toException()
}
}
}
suspend fun <T: Any> DatabaseReference.getDataFromDatabaseRef(clazz : Class<T>): T? {
return when (val response: EventResponse = singleValueEvent()) {
is EventResponse.Changed -> {
response.snapshot.getValue(clazz)
}
is EventResponse.Cancelled -> {
throw response.error.toException()
}
}
}

View File

@@ -0,0 +1,52 @@
package h_mal.appttude.com.driver.utils
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.viewbinding.ViewBinding
import java.lang.reflect.ParameterizedType
import kotlin.reflect.KClass
object GenericsHelper {
@Suppress("UNCHECKED_CAST")
fun <CLASS : Any> Any.getGenericClassAt(position: Int): KClass<CLASS> =
((javaClass.genericSuperclass as? ParameterizedType)
?.actualTypeArguments?.getOrNull(position) as? Class<CLASS>)
?.kotlin
?: throw IllegalStateException("Can not find class from generic argument")
/**
* Create a view binding out of the the generic [VB]
*
* @sample inflateBindingByType(getGenericClassAt(0), layoutInflater)
*/
fun <VB: ViewBinding> inflateBindingByType(
genericClassAt: KClass<VB>,
layoutInflater: LayoutInflater
): VB = try {
@Suppress("UNCHECKED_CAST")
genericClassAt.java.methods.first { viewBinding ->
viewBinding.parameterTypes.size == 1
&& viewBinding.parameterTypes.getOrNull(0) == LayoutInflater::class.java
}.invoke(null, layoutInflater) as VB
} catch (exception: Exception) {
println ("generic class failed at = $genericClassAt")
exception.printStackTrace()
throw IllegalStateException("Can not inflate binding from generic")
}
fun <VB: ViewBinding> LayoutInflater.inflateBindingByType(
container: ViewGroup?,
genericClassAt: KClass<VB>
): VB = try {
@Suppress("UNCHECKED_CAST")
genericClassAt.java.methods.first { inflateFun ->
inflateFun.parameterTypes.size == 3
&& inflateFun.parameterTypes.getOrNull(0) == LayoutInflater::class.java
&& inflateFun.parameterTypes.getOrNull(1) == ViewGroup::class.java
&& inflateFun.parameterTypes.getOrNull(2) == Boolean::class.java
}.invoke(null, this, container, false) as VB
} catch (exception: Exception) {
throw IllegalStateException("Can not inflate binding from generic")
}
}

View File

@@ -1,28 +1,29 @@
package h_mal.appttude.com.driver.utils
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.Parcelable
import android.view.View
import androidx.annotation.IdRes
import androidx.navigation.Navigation
const val UPLOAD_NEW = "upload_new"
fun View.navigateTo(@IdRes navId: Int, args: Bundle? = null) {
Navigation
.findNavController(this)
.navigate(navId, args)
}
fun Any.toBundle(key: String): Bundle {
return Bundle().apply {
when (this@toBundle) {
is String -> putString(key, this@toBundle)
is Int -> putInt(key, this@toBundle)
is Boolean -> putBoolean(key, this@toBundle)
is Parcelable -> putParcelable(key, this@toBundle)
is Double -> putDouble(key, this@toBundle)
is Float -> putFloat(key, this@toBundle)
}
fun navigateToActivity(context: Context, navigationActivity: Navigations) {
try {
val ourClass: Class<*> =
Class.forName("h_mal.appttude.com.driver." + navigationActivity.value)
val intent = Intent(context, ourClass)
context.startActivity(intent)
} catch (e: Exception) {
e.printStackTrace()
}
}
fun View.navigateTo(@IdRes navId: Int) {
Navigation
.findNavController(this)
.navigate(navId)
}

View File

@@ -1,33 +0,0 @@
package h_mal.appttude.com.driver.viewmodels
import android.net.Uri
import com.google.firebase.database.DatabaseReference
import com.google.firebase.storage.StorageReference
import h_mal.appttude.com.driver.base.DataSubmissionBaseViewModel
import h_mal.appttude.com.driver.data.FirebaseAuthentication
import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
import h_mal.appttude.com.driver.data.FirebaseStorageSource
import h_mal.appttude.com.driver.model.DriversLicense
import h_mal.appttude.com.driver.utils.Coroutines.io
class DriverLicenseViewModel(
auth: FirebaseAuthentication,
database: FirebaseDatabaseSource,
storage: FirebaseStorageSource
) : DataSubmissionBaseViewModel<DriversLicense>(auth, database, storage) {
override val databaseRef: DatabaseReference = database.getDriverLicenseRef(uid)
override val storageRef: StorageReference = storage.driversLicenseStorageRef(uid)
override val objectName: String = "drivers license"
override fun getDataFromDatabase() = getDataClass<DriversLicense>()
override fun setDataInDatabase(data: DriversLicense, localImageUri: Uri?) = io {
doTryOperation("Failed to upload $objectName") {
val imageUrl = getImageUrl(localImageUri, data.licenseImageString)
data.licenseImageString = imageUrl
postDataToDatabase(data)
}
}
}

View File

@@ -1,35 +0,0 @@
package h_mal.appttude.com.driver.viewmodels
import android.net.Uri
import com.google.firebase.database.DatabaseReference
import com.google.firebase.storage.StorageReference
import h_mal.appttude.com.driver.base.DataSubmissionBaseViewModel
import h_mal.appttude.com.driver.data.FirebaseAuthentication
import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
import h_mal.appttude.com.driver.data.FirebaseStorageSource
import h_mal.appttude.com.driver.model.DriverProfile
import h_mal.appttude.com.driver.utils.Coroutines.io
class DriverProfileViewModel(
auth: FirebaseAuthentication,
database: FirebaseDatabaseSource,
storage: FirebaseStorageSource
) : DataSubmissionBaseViewModel<DriverProfile>(auth, database, storage) {
override val databaseRef: DatabaseReference = database.getDriverDetailsRef(uid)
override val storageRef: StorageReference = storage.profileImageStorageRef(uid)
override val objectName: String = "drivers profile"
override fun getDataFromDatabase() = getDataClass<DriverProfile>()
override fun setDataInDatabase(data: DriverProfile, localImageUri: Uri?) = io {
doTryOperation("Failed to upload $objectName") {
val imageUrl = getImageUrl(localImageUri, data.driverPic)
data.driverPic = imageUrl
postDataToDatabase(data)
}
}
}

View File

@@ -1,41 +0,0 @@
package h_mal.appttude.com.driver.viewmodels
import android.net.Uri
import com.google.firebase.database.DatabaseReference
import com.google.firebase.storage.StorageReference
import h_mal.appttude.com.driver.base.DataSubmissionBaseViewModel
import h_mal.appttude.com.driver.data.FirebaseAuthentication
import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
import h_mal.appttude.com.driver.data.FirebaseStorageSource
import h_mal.appttude.com.driver.model.Insurance
import h_mal.appttude.com.driver.utils.Coroutines.io
class InsuranceViewModel(
auth: FirebaseAuthentication,
database: FirebaseDatabaseSource,
storage: FirebaseStorageSource
) : DataSubmissionBaseViewModel<Insurance>(auth, database, storage) {
override val databaseRef: DatabaseReference = database.getInsuranceDetailsRef(uid)
override val storageRef: StorageReference = storage.insuranceStorageRef(uid)
override val objectName: String = "insurance"
override fun getDataFromDatabase() = getDataClass<Insurance>()
override fun setDataInDatabase(data: Insurance, localImageUris: List<Uri?>?) = io {
doTryOperation("Failed to upload $objectName") {
val imageUrls = if (!localImageUris.isNullOrEmpty()) {
getImageUrls(localImageUris).toMutableList()
} else {
data.photoStrings
}
if (imageUrls.isNullOrEmpty()) {
onError("no images selected")
return@doTryOperation
}
data.photoStrings = imageUrls
postDataToDatabase(data)
}
}
}

View File

@@ -1,33 +0,0 @@
package h_mal.appttude.com.driver.viewmodels
import android.net.Uri
import com.google.firebase.database.DatabaseReference
import com.google.firebase.storage.StorageReference
import h_mal.appttude.com.driver.base.DataSubmissionBaseViewModel
import h_mal.appttude.com.driver.data.FirebaseAuthentication
import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
import h_mal.appttude.com.driver.data.FirebaseStorageSource
import h_mal.appttude.com.driver.model.Logbook
import h_mal.appttude.com.driver.utils.Coroutines.io
class LogbookViewModel(
auth: FirebaseAuthentication,
database: FirebaseDatabaseSource,
storage: FirebaseStorageSource
) : DataSubmissionBaseViewModel<Logbook>(auth, database, storage) {
override val databaseRef: DatabaseReference = database.getLogbookRef(uid)
override val storageRef: StorageReference = storage.logBookStorageRef(uid)
override val objectName: String = "Log book"
override fun getDataFromDatabase() = getDataClass<Logbook>()
override fun setDataInDatabase(data: Logbook, localImageUri: Uri?) = io {
doTryOperation("Failed to upload $objectName") {
val imageUrl = getImageUrl(localImageUri, data.photoString)
data.photoString = imageUrl
postDataToDatabase(data)
}
}
}

View File

@@ -1,33 +0,0 @@
package h_mal.appttude.com.driver.viewmodels
import android.net.Uri
import com.google.firebase.database.DatabaseReference
import com.google.firebase.storage.StorageReference
import h_mal.appttude.com.driver.base.DataSubmissionBaseViewModel
import h_mal.appttude.com.driver.data.FirebaseAuthentication
import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
import h_mal.appttude.com.driver.data.FirebaseStorageSource
import h_mal.appttude.com.driver.model.Mot
import h_mal.appttude.com.driver.utils.Coroutines.io
class MotViewModel(
auth: FirebaseAuthentication,
database: FirebaseDatabaseSource,
storage: FirebaseStorageSource
) : DataSubmissionBaseViewModel<Mot>(auth, database, storage) {
override val databaseRef: DatabaseReference = database.getMotDetailsRef(uid)
override val storageRef: StorageReference? = storage.motStorageRef(uid)
override val objectName: String = "vehicle profile"
override fun getDataFromDatabase() = getDataClass<Mot>()
override fun setDataInDatabase(data: Mot, localImageUri: Uri?) = io {
doTryOperation("Failed to upload $objectName") {
val imageUrl = getImageUrl(localImageUri, data.motImageString)
data.motImageString = imageUrl
postDataToDatabase(data)
}
}
}

View File

@@ -1,38 +0,0 @@
package h_mal.appttude.com.driver.viewmodels
import android.net.Uri
import com.google.firebase.database.DatabaseReference
import com.google.firebase.storage.StorageReference
import h_mal.appttude.com.driver.base.DataSubmissionBaseViewModel
import h_mal.appttude.com.driver.data.FirebaseAuthentication
import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
import h_mal.appttude.com.driver.data.FirebaseStorageSource
import h_mal.appttude.com.driver.model.PrivateHireLicense
import h_mal.appttude.com.driver.utils.Coroutines.io
class PrivateHireLicenseViewModel(
auth: FirebaseAuthentication,
database: FirebaseDatabaseSource,
storage: FirebaseStorageSource
) : DataSubmissionBaseViewModel<PrivateHireLicense>(auth, database, storage) {
override val databaseRef: DatabaseReference = database.getPrivateHireRef(uid)
override val storageRef: StorageReference = storage.privateHireStorageRef(uid)
override val objectName: String = "private hire license"
override fun getDataFromDatabase() = getDataClass<PrivateHireLicense>()
override fun setDataInDatabase(data: PrivateHireLicense, localImageUri: Uri?) = io {
doTryOperation("Failed to upload private hire license") {
val imageUrl = getImageUrl(localImageUri, data.phImageString)
val driverLicense = PrivateHireLicense(
phExpiry = data.phExpiry,
phNumber = data.phNumber,
phImageString = imageUrl
)
postDataToDatabase(driverLicense)
}
}
}

View File

@@ -1,32 +0,0 @@
package h_mal.appttude.com.driver.viewmodels
import android.net.Uri
import com.google.firebase.database.DatabaseReference
import com.google.firebase.storage.StorageReference
import h_mal.appttude.com.driver.base.DataSubmissionBaseViewModel
import h_mal.appttude.com.driver.data.FirebaseAuthentication
import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
import h_mal.appttude.com.driver.data.FirebaseStorageSource
import h_mal.appttude.com.driver.model.PrivateHireVehicle
import h_mal.appttude.com.driver.utils.Coroutines.io
class PrivateHireVehicleViewModel(
auth: FirebaseAuthentication,
database: FirebaseDatabaseSource,
storage: FirebaseStorageSource
) : DataSubmissionBaseViewModel<PrivateHireVehicle>(auth, database, storage) {
override val databaseRef: DatabaseReference = database.getPrivateHireVehicleRef(uid)
override val storageRef: StorageReference = storage.privateHireVehicleStorageRef(uid)
override val objectName: String = "private hire vehicle license"
override fun getDataFromDatabase() = getDataClass<PrivateHireVehicle>()
override fun setDataInDatabase(data: PrivateHireVehicle, localImageUri: Uri?) = io {
doTryOperation("Failed to upload $objectName") {
val imageUrl = getImageUrl(localImageUri, data.phCarImageString)
data.phCarImageString = imageUrl
postDataToDatabase(data)
}
}
}

View File

@@ -18,7 +18,7 @@ class RoleViewModel(
override val storageRef: StorageReference? = null
override val objectName: String = "role"
override fun getDataFromDatabase() = getDataClass<String>()
override fun getDataFromDatabase() = retrieveDataFromDatabase<String>()
override fun setDataInDatabase(data: String) {
io {

View File

@@ -1,33 +0,0 @@
package h_mal.appttude.com.driver.viewmodels
import com.google.firebase.database.DatabaseReference
import com.google.firebase.storage.StorageReference
import h_mal.appttude.com.driver.base.DataSubmissionBaseViewModel
import h_mal.appttude.com.driver.data.FirebaseAuthentication
import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
import h_mal.appttude.com.driver.data.FirebaseStorageSource
import h_mal.appttude.com.driver.model.VehicleProfile
import h_mal.appttude.com.driver.utils.Coroutines.io
class VehicleProfileViewModel(
auth: FirebaseAuthentication,
database: FirebaseDatabaseSource,
storage: FirebaseStorageSource
) : DataSubmissionBaseViewModel<VehicleProfile>(auth, database, storage) {
override val databaseRef: DatabaseReference = database.getVehicleDetailsRef(uid)
override val storageRef: StorageReference? = null
override val objectName: String = "vehicle profile"
override fun getDataFromDatabase() = getDataClass<VehicleProfile>()
override fun setDataInDatabase(data: VehicleProfile) {
io {
doTryOperation("Failed to upload $objectName") {
postDataToDatabase(data)
}
}
}
}

View File

@@ -1,46 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
android:id="@+id/app_bar_layout"
layout="@layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:itemTextColor="@android:color/white"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="vertical">
<TextView
android:id="@+id/logout"
style="@style/headerStyle"
android:background="@color/colour_nine"
android:textSize="14sp"
android:layout_width="match_parent"
android:layout_height="48dp"
android:gravity="center"
android:text="@string/logout"
android:textStyle="bold" />
</LinearLayout>
</com.google.android.material.navigation.NavigationView>
</androidx.drawerlayout.widget.DrawerLayout>

View File

@@ -18,22 +18,9 @@
android:layout_marginBottom="24dp"
android:text="@string/not_a_driver_message" />
<androidx.cardview.widget.CardView
<com.google.android.material.button.MaterialButton
android:id="@+id/request_driver_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="@color/colour_one"
android:selectAllOnFocus="true"
app:cardCornerRadius="8dp">
style="@style/TextButton"
android:text="@string/request_driver_profile" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:gravity="center"
android:text="@string/request_driver_profile"
android:textColor="@android:color/white"
android:textSize="18sp"
android:textStyle="bold" />
</androidx.cardview.widget.CardView>
</LinearLayout>

View File

@@ -46,7 +46,8 @@
tools:src="@drawable/choice_img_round" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.textfield.TextInputLayout style="@style/text_input_layout">
<com.google.android.material.textfield.TextInputLayout
style="@style/text_input_layout">
<EditText
android:id="@+id/names_input"

View File

@@ -4,9 +4,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
style="@style/parent_constraint_layout"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".ui.vehicleprofile.LogbookFragment">
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.cardview.widget.CardView
android:layout_width="wrap_content"

View File

@@ -2,8 +2,7 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
style="@style/parent_constraint_layout"
tools:context=".ui.vehicleprofile.PrivateHireVehicleFragment">
style="@style/parent_constraint_layout">
<androidx.cardview.widget.CardView
android:layout_width="wrap_content"

View File

@@ -2,9 +2,7 @@
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
tools:context=".ui.vehicleprofile.VehicleProfileFragment">
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"

View File

@@ -5,6 +5,6 @@
<item
android:id="@+id/archive"
android:icon="@drawable/ic_sort_black_24dp"
android:title="sort"
app:showAsAction="ifRoom"></item>
android:title="@string/sort"
app:showAsAction="ifRoom" />
</menu>

View File

@@ -14,5 +14,6 @@
<color name="colour_seven">#91ddff</color>
<color name="colour_eight">#9958BE3F</color>
<color name="colour_ten">#604D4A51</color>
<color name="colour_nine">#303030</color>
</resources>

View File

@@ -4,4 +4,5 @@
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="nav_header_vertical_spacing">8dp</dimen>
<dimen name="nav_header_height">200dp</dimen>
<dimen name="status_size">16dp</dimen>
</resources>

View File

@@ -1,5 +1,4 @@
<resources>
<string name="app_name">Choice Minicabs</string>
<string name="nav_header_title">Driver Name</string>
<string name="nav_header_subtitle">driver@example.com</string>
<string name="nav_header_desc">Navigation header</string>
@@ -83,7 +82,7 @@
<string name="insurance">Insurance</string>
<string name="m_o_t">M.O.T</string>
<string name="log_book">Log book</string>
<string name="private_hire_vehicle_license">Private hire Vehicle License</string>
<string name="private_hire_vehicle_license">Private Hire Vehicle License</string>
<string name="upload_insurance_documents">Upload Insurance Documents</string>
<string name="insurer">Insurer</string>
<string name="insurance_expiry">Insurance expiry</string>
@@ -95,4 +94,11 @@
<string name="request_driver_profile">Request driver profile</string>
<string name="or">OR</string>
<string name="floating_action_button">Floating action button</string>
<string name="sort">sort</string>
<string name="denied">Approval denied</string>
<string name="pending">Pending approval</string>
<string name="approved">Approved</string>
<string name="not_submitted">Not submitted</string>
<string name="empty_view_message">You have no drivers</string>
<string name="approval_status">approval status</string>
</resources>