mirror of
https://github.com/hmalik144/Farmr.git
synced 2026-03-18 07:25:55 +00:00
- mid commit
This commit is contained in:
@@ -1,26 +1,10 @@
|
||||
package com.appttude.h_mal.farmr.base
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.ViewModelLazy
|
||||
import com.appttude.h_mal.farmr.utils.displayToast
|
||||
import com.appttude.h_mal.farmr.utils.getGenericClassAt
|
||||
import com.appttude.h_mal.farmr.viewmodel.ApplicationViewModelFactory
|
||||
import org.kodein.di.KodeinAware
|
||||
import org.kodein.di.android.kodein
|
||||
import org.kodein.di.generic.instance
|
||||
|
||||
abstract class BaseActivity<V : BaseViewModel> : AppCompatActivity(), KodeinAware {
|
||||
|
||||
override val kodein by kodein()
|
||||
private val factory by instance<ApplicationViewModelFactory>()
|
||||
|
||||
val viewModel: V by getViewModel()
|
||||
|
||||
private fun getViewModel(): Lazy<V> =
|
||||
ViewModelLazy(getGenericClassAt(0), storeProducer = { viewModelStore },
|
||||
factoryProducer = { factory } )
|
||||
abstract class BaseActivity : AppCompatActivity() {
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,11 +5,13 @@ import android.view.View
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.createViewModelLazy
|
||||
import androidx.lifecycle.ViewModelLazy
|
||||
import com.appttude.h_mal.farmr.model.ViewState
|
||||
import com.appttude.h_mal.farmr.utils.getGenericClassAt
|
||||
import com.appttude.h_mal.farmr.utils.popBackStack
|
||||
import com.appttude.h_mal.farmr.viewmodel.ApplicationViewModelFactory
|
||||
import org.kodein.di.KodeinAware
|
||||
import org.kodein.di.android.kodein
|
||||
import org.kodein.di.android.x.kodein
|
||||
import org.kodein.di.generic.instance
|
||||
import kotlin.properties.Delegates
|
||||
@@ -21,14 +23,13 @@ abstract class BaseFragment<V : BaseViewModel>(@LayoutRes contentLayoutId: Int)
|
||||
override val kodein by kodein()
|
||||
private val factory by instance<ApplicationViewModelFactory>()
|
||||
|
||||
val viewModel: V by getActivityViewModel()
|
||||
val viewModel: V by getViewModel()
|
||||
|
||||
private fun getActivityViewModel() = createViewModelLazy<V>(
|
||||
getGenericClassAt(0),
|
||||
{ requireActivity().viewModelStore },
|
||||
{ factory })
|
||||
private fun getViewModel(): Lazy<V> =
|
||||
ViewModelLazy(getGenericClassAt(0), storeProducer = { viewModelStore },
|
||||
factoryProducer = { factory } )
|
||||
|
||||
var mActivity: BaseActivity<*>? = null
|
||||
var mActivity: BaseActivity? = null
|
||||
|
||||
private var shortAnimationDuration by Delegates.notNull<Int>()
|
||||
|
||||
@@ -39,7 +40,7 @@ abstract class BaseFragment<V : BaseViewModel>(@LayoutRes contentLayoutId: Int)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
mActivity = requireActivity() as BaseActivity<*>
|
||||
mActivity = requireActivity() as BaseActivity
|
||||
configureObserver()
|
||||
}
|
||||
|
||||
@@ -75,7 +76,7 @@ abstract class BaseFragment<V : BaseViewModel>(@LayoutRes contentLayoutId: Int)
|
||||
}
|
||||
|
||||
fun setTitle(title: String) {
|
||||
(requireActivity() as BaseActivity<*>).setTitleInActionBar(title)
|
||||
(requireActivity() as BaseActivity).setTitleInActionBar(title)
|
||||
}
|
||||
|
||||
fun popBackStack() = mActivity?.popBackStack()
|
||||
|
||||
@@ -13,8 +13,8 @@ const val SORT = "SORT"
|
||||
const val ORDER = "ORDER"
|
||||
|
||||
const val DESCRIPTION = "DESCRIPTION"
|
||||
const val TIME_IN = "TIME_IN"
|
||||
const val TIME_OUT = "TIME_OUT"
|
||||
const val DATE_IN = "TIME_IN"
|
||||
const val DATE_OUT = "TIME_OUT"
|
||||
const val TYPE = "TYPE"
|
||||
|
||||
class PreferenceProvider(
|
||||
@@ -47,8 +47,8 @@ class PreferenceProvider(
|
||||
) {
|
||||
preference.edit()
|
||||
.putString(DESCRIPTION, description)
|
||||
.putString(TIME_IN, timeIn)
|
||||
.putString(TIME_OUT, timeOut)
|
||||
.putString(DATE_IN, timeIn)
|
||||
.putString(DATE_OUT, timeOut)
|
||||
.putString(TYPE, type)
|
||||
.apply()
|
||||
}
|
||||
@@ -56,8 +56,8 @@ class PreferenceProvider(
|
||||
fun getFilteringDetails(): Map<String, String?> {
|
||||
return mapOf(
|
||||
Pair(DESCRIPTION, preference.getString(DESCRIPTION, null)),
|
||||
Pair(TIME_IN, preference.getString(TIME_IN, null)),
|
||||
Pair(TIME_OUT, preference.getString(TIME_OUT, null)),
|
||||
Pair(DATE_IN, preference.getString(DATE_IN, null)),
|
||||
Pair(DATE_OUT, preference.getString(DATE_OUT, null)),
|
||||
Pair(TYPE, preference.getString(TYPE, null))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -14,9 +14,9 @@ import com.appttude.h_mal.farmr.base.BaseFragment
|
||||
import com.appttude.h_mal.farmr.model.ShiftType
|
||||
import com.appttude.h_mal.farmr.model.Success
|
||||
import com.appttude.h_mal.farmr.utils.setDatePicker
|
||||
import com.appttude.h_mal.farmr.viewmodel.MainViewModel
|
||||
import com.appttude.h_mal.farmr.viewmodel.FilterViewModel
|
||||
|
||||
class FilterDataFragment : BaseFragment<MainViewModel>(R.layout.fragment_filter_data),
|
||||
class FilterDataFragment : BaseFragment<FilterViewModel>(R.layout.fragment_filter_data),
|
||||
AdapterView.OnItemSelectedListener, OnClickListener {
|
||||
private val spinnerList: Array<String> =
|
||||
arrayOf("", ShiftType.HOURLY.type, ShiftType.PIECE.type)
|
||||
@@ -26,10 +26,10 @@ class FilterDataFragment : BaseFragment<MainViewModel>(R.layout.fragment_filter_
|
||||
private lateinit var dateToET: EditText
|
||||
private lateinit var typeSpinner: Spinner
|
||||
|
||||
private var description: String? = null
|
||||
private var dateFrom: String? = null
|
||||
private var dateTo: String? = null
|
||||
private var type: String? = null
|
||||
private var descriptionString: String? = null
|
||||
private var dateFromString: String? = null
|
||||
private var dateToString: String? = null
|
||||
private var typeString: String? = null
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
@@ -47,21 +47,29 @@ class FilterDataFragment : BaseFragment<MainViewModel>(R.layout.fragment_filter_
|
||||
|
||||
val filterDetails = viewModel.getFiltrationDetails()
|
||||
|
||||
filterDetails.let {
|
||||
LocationET.setText(it.description)
|
||||
dateFromET.setText(it.dateFrom)
|
||||
dateToET.setText(it.dateTo)
|
||||
|
||||
it.type?.let { t ->
|
||||
val spinnerPosition: Int = adapter.getPosition(t)
|
||||
filterDetails.run {
|
||||
description?.let {
|
||||
LocationET.setText(it)
|
||||
descriptionString = it
|
||||
}
|
||||
dateFrom?.let {
|
||||
dateFromET.setText(it)
|
||||
dateFromString = it
|
||||
}
|
||||
dateTo?.let {
|
||||
dateToET.setText(it)
|
||||
dateToString = it
|
||||
}
|
||||
type?.let {
|
||||
typeString = it
|
||||
val spinnerPosition: Int = adapter.getPosition(it)
|
||||
typeSpinner.setSelection(spinnerPosition)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
LocationET.doAfterTextChanged { description = it.toString() }
|
||||
dateFromET.setDatePicker { dateFrom = it }
|
||||
dateToET.setDatePicker { dateTo = it }
|
||||
LocationET.doAfterTextChanged { descriptionString = it.toString() }
|
||||
dateFromET.setDatePicker { dateFromString = it }
|
||||
dateToET.setDatePicker { dateToString = it }
|
||||
typeSpinner.onItemSelectedListener = this
|
||||
|
||||
submit.setOnClickListener(this)
|
||||
@@ -73,7 +81,7 @@ class FilterDataFragment : BaseFragment<MainViewModel>(R.layout.fragment_filter_
|
||||
position: Int,
|
||||
id: Long
|
||||
) {
|
||||
type = when (position) {
|
||||
typeString = when (position) {
|
||||
1 -> ShiftType.HOURLY.type
|
||||
2 -> ShiftType.PIECE.type
|
||||
else -> return
|
||||
@@ -83,7 +91,7 @@ class FilterDataFragment : BaseFragment<MainViewModel>(R.layout.fragment_filter_
|
||||
override fun onNothingSelected(parentView: AdapterView<*>?) {}
|
||||
|
||||
private fun submitFiltrationDetails() {
|
||||
viewModel.setFiltrationDetails(description, dateFrom, dateTo, type)
|
||||
viewModel.applyFilters(descriptionString, dateFromString, dateToString, typeString)
|
||||
}
|
||||
|
||||
override fun onClick(p0: View?) {
|
||||
|
||||
@@ -26,8 +26,9 @@ import com.appttude.h_mal.farmr.utils.setTimePicker
|
||||
import com.appttude.h_mal.farmr.utils.show
|
||||
import com.appttude.h_mal.farmr.utils.validateField
|
||||
import com.appttude.h_mal.farmr.viewmodel.MainViewModel
|
||||
import com.appttude.h_mal.farmr.viewmodel.SubmissionViewModel
|
||||
|
||||
class FragmentAddItem : BaseFragment<MainViewModel>(R.layout.fragment_add_item),
|
||||
class FragmentAddItem : BaseFragment<SubmissionViewModel>(R.layout.fragment_add_item),
|
||||
RadioGroup.OnCheckedChangeListener, BackPressedListener {
|
||||
|
||||
private lateinit var mHourlyRadioButton: RadioButton
|
||||
@@ -262,7 +263,6 @@ class FragmentAddItem : BaseFragment<MainViewModel>(R.layout.fragment_add_item),
|
||||
StringBuilder().append(mDuration).append(" hours").toString()
|
||||
mDuration!! * mPayRate
|
||||
}
|
||||
|
||||
ShiftType.PIECE -> {
|
||||
(mUnits ?: 0f) * mPayRate
|
||||
}
|
||||
|
||||
@@ -70,7 +70,6 @@ class FragmentMain : BaseFragment<MainViewModel>(R.layout.fragment_main), BackPr
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
|
||||
viewModel.refreshLiveData()
|
||||
}
|
||||
|
||||
@@ -112,7 +111,7 @@ class FragmentMain : BaseFragment<MainViewModel>(R.layout.fragment_main), BackPr
|
||||
}
|
||||
|
||||
R.id.clear_filter -> {
|
||||
viewModel.setFiltrationDetails(null, null, null, null)
|
||||
viewModel.clearFilters()
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -11,13 +11,14 @@ import com.appttude.h_mal.farmr.base.BaseFragment
|
||||
import com.appttude.h_mal.farmr.data.legacydb.ShiftObject
|
||||
import com.appttude.h_mal.farmr.model.ShiftType
|
||||
import com.appttude.h_mal.farmr.utils.CURRENCY
|
||||
import com.appttude.h_mal.farmr.utils.ID
|
||||
import com.appttude.h_mal.farmr.utils.formatAsCurrencyString
|
||||
import com.appttude.h_mal.farmr.utils.formatToTwoDpString
|
||||
import com.appttude.h_mal.farmr.utils.hide
|
||||
import com.appttude.h_mal.farmr.utils.navigateToFragment
|
||||
import com.appttude.h_mal.farmr.utils.show
|
||||
import com.appttude.h_mal.farmr.viewmodel.MainViewModel
|
||||
import com.appttude.h_mal.farmr.viewmodel.InfoViewModel
|
||||
|
||||
class FurtherInfoFragment : BaseFragment<MainViewModel>(R.layout.fragment_futher_info) {
|
||||
class FurtherInfoFragment : BaseFragment<InfoViewModel>(R.layout.fragment_futher_info) {
|
||||
private lateinit var typeTV: TextView
|
||||
private lateinit var descriptionTV: TextView
|
||||
private lateinit var dateTV: TextView
|
||||
@@ -52,60 +53,50 @@ class FurtherInfoFragment : BaseFragment<MainViewModel>(R.layout.fragment_futher
|
||||
hourlyDetailHolder = view.findViewById(R.id.details_hourly_details)
|
||||
unitsHolder = view.findViewById(R.id.details_units_holder)
|
||||
|
||||
val id = arguments!!.getLong(ID)
|
||||
|
||||
editButton.setOnClickListener {
|
||||
navigateToFragment(FragmentAddItem(), name = "additem", bundle = arguments!!)
|
||||
}
|
||||
|
||||
setupView(id)
|
||||
viewModel.retrieveData(arguments)
|
||||
}
|
||||
|
||||
private fun setupView(id: Long) {
|
||||
viewModel.getCurrentShift(id)?.run {
|
||||
typeTV.text = type
|
||||
descriptionTV.text = description
|
||||
dateTV.text = date
|
||||
payRateTV.text = rateOfPay.toString()
|
||||
totalPayTV.text = StringBuilder(CURRENCY).append(totalPay).toString()
|
||||
override fun onSuccess(data: Any?) {
|
||||
super.onSuccess(data)
|
||||
if (data is ShiftObject) data.setupView()
|
||||
}
|
||||
|
||||
when (ShiftType.getEnumByType(type)) {
|
||||
ShiftType.HOURLY -> {
|
||||
hourlyDetailHolder.show()
|
||||
unitsHolder.hide()
|
||||
times.text = StringBuilder(timeIn).append("-").append(timeOut).toString()
|
||||
breakTV.text = StringBuilder(breakMins).append("mins").toString()
|
||||
durationTV.text = buildDurationSummary(this)
|
||||
val paymentSummary =
|
||||
StringBuilder().append(duration).append(" Hours @ ").append(CURRENCY)
|
||||
.append(rateOfPay).append(" per Hour").append("\n")
|
||||
.append("Equals: ").append(CURRENCY).append(totalPay)
|
||||
totalPayTV.text = paymentSummary
|
||||
}
|
||||
private fun ShiftObject.setupView() {
|
||||
typeTV.text = type
|
||||
descriptionTV.text = description
|
||||
dateTV.text = date
|
||||
payRateTV.text = rateOfPay.toString()
|
||||
totalPayTV.text = StringBuilder(CURRENCY).append(totalPay).toString()
|
||||
|
||||
ShiftType.PIECE -> {
|
||||
hourlyDetailHolder.hide()
|
||||
unitsHolder.show()
|
||||
unitsTV.text = units.toString()
|
||||
when (ShiftType.getEnumByType(type)) {
|
||||
ShiftType.HOURLY -> {
|
||||
hourlyDetailHolder.show()
|
||||
unitsHolder.hide()
|
||||
times.text = StringBuilder(timeIn).append("-").append(timeOut).toString()
|
||||
breakTV.text = StringBuilder().append(breakMins).append(" mins").toString()
|
||||
durationTV.text = viewModel.buildDurationSummary(this)
|
||||
val paymentSummary =
|
||||
StringBuilder().append(duration).append(" Hours @ ")
|
||||
.append(rateOfPay.formatAsCurrencyString()).append(" per Hour").append("\n")
|
||||
.append("Equals: ").append(totalPay.formatAsCurrencyString())
|
||||
totalPayTV.text = paymentSummary
|
||||
}
|
||||
|
||||
val paymentSummary =
|
||||
StringBuilder().append(units).append(" Units @ ").append(CURRENCY)
|
||||
.append(rateOfPay).append(" per Unit").append("\n")
|
||||
.append("Equals: ").append(CURRENCY).append(totalPay)
|
||||
totalPayTV.text = paymentSummary
|
||||
}
|
||||
ShiftType.PIECE -> {
|
||||
hourlyDetailHolder.hide()
|
||||
unitsHolder.show()
|
||||
unitsTV.text = units.toString()
|
||||
|
||||
val paymentSummary =
|
||||
StringBuilder().append(units.formatAsCurrencyString()).append(" Units @ ")
|
||||
.append(rateOfPay.formatAsCurrencyString()).append(" per Unit").append("\n")
|
||||
.append("Equals: ").append(totalPay.formatAsCurrencyString())
|
||||
totalPayTV.text = paymentSummary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildDurationSummary(shiftObject: ShiftObject): String {
|
||||
val time = shiftObject.getHoursMinutesPairFromDuration()
|
||||
|
||||
val stringBuilder = StringBuilder().append(time.first).append(" Hours ").append(time.second)
|
||||
.append(" Minutes ")
|
||||
if (shiftObject.breakMins > 0) {
|
||||
stringBuilder.append(" (+ ").append(shiftObject.breakMins).append(" minutes break)")
|
||||
}
|
||||
return stringBuilder.toString()
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ import com.appttude.h_mal.farmr.utils.popBackStack
|
||||
import com.appttude.h_mal.farmr.viewmodel.MainViewModel
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
class MainActivity : BaseActivity<MainViewModel>() {
|
||||
class MainActivity : BaseActivity() {
|
||||
private lateinit var toolbar: Toolbar
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package com.appttude.h_mal.farmr.utils
|
||||
|
||||
import java.io.IOException
|
||||
import java.text.NumberFormat
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Currency
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
@@ -16,6 +18,14 @@ fun Float.formatToTwoDp(): Float {
|
||||
return formattedString.toFloat()
|
||||
}
|
||||
|
||||
fun Float.formatAsCurrencyString(): String? {
|
||||
val format: NumberFormat = NumberFormat.getCurrencyInstance()
|
||||
format.maximumFractionDigits = 2
|
||||
format.currency = Currency.getInstance("GBP")
|
||||
|
||||
return format.format(this)
|
||||
}
|
||||
|
||||
fun Float.formatToTwoDpString(): String {
|
||||
return formatToTwoDp().toString()
|
||||
}
|
||||
|
||||
@@ -14,6 +14,9 @@ class ApplicationViewModelFactory(
|
||||
with(modelClass) {
|
||||
return when {
|
||||
isAssignableFrom(MainViewModel::class.java) -> MainViewModel(repository)
|
||||
isAssignableFrom(SubmissionViewModel::class.java) -> SubmissionViewModel(repository)
|
||||
isAssignableFrom(InfoViewModel::class.java) -> InfoViewModel(repository)
|
||||
isAssignableFrom(FilterViewModel::class.java) -> FilterViewModel(repository)
|
||||
else -> throw IllegalArgumentException("Unknown ViewModel class")
|
||||
} as T
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.appttude.h_mal.farmr.viewmodel
|
||||
|
||||
import com.appttude.h_mal.farmr.data.Repository
|
||||
import com.appttude.h_mal.farmr.model.Success
|
||||
|
||||
|
||||
class FilterViewModel(
|
||||
repository: Repository
|
||||
) : ShiftViewModel(repository) {
|
||||
|
||||
fun applyFilters(
|
||||
description: String?,
|
||||
dateFrom: String?,
|
||||
dateTo: String?,
|
||||
type: String?
|
||||
) {
|
||||
super.setFiltrationDetails(description, dateFrom, dateTo, type)
|
||||
onSuccess(Success("Filter(s) have been applied"))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.appttude.h_mal.farmr.viewmodel
|
||||
|
||||
import android.os.Bundle
|
||||
import com.appttude.h_mal.farmr.data.Repository
|
||||
import com.appttude.h_mal.farmr.data.legacydb.ShiftObject
|
||||
import com.appttude.h_mal.farmr.utils.ID
|
||||
|
||||
|
||||
class InfoViewModel(
|
||||
repository: Repository
|
||||
) : ShiftViewModel(repository) {
|
||||
|
||||
fun retrieveData(bundle: Bundle?) {
|
||||
val id = bundle?.getLong(ID)
|
||||
if (id == null) {
|
||||
onError("Failed to retrieve shift")
|
||||
return
|
||||
}
|
||||
|
||||
val shift = getCurrentShift(id)
|
||||
if (shift == null) {
|
||||
onError("Failed to retrieve shift")
|
||||
return
|
||||
}
|
||||
|
||||
onSuccess(shift)
|
||||
}
|
||||
|
||||
fun buildDurationSummary(shiftObject: ShiftObject): String {
|
||||
val time = shiftObject.getHoursMinutesPairFromDuration()
|
||||
|
||||
val stringBuilder = StringBuilder().append(time.first).append(" Hours ").append(time.second)
|
||||
.append(" Minutes ")
|
||||
if (shiftObject.breakMins > 0) {
|
||||
stringBuilder.append(" (+ ").append(shiftObject.breakMins).append(" minutes break)")
|
||||
}
|
||||
return stringBuilder.toString()
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,10 @@
|
||||
package com.appttude.h_mal.farmr.viewmodel
|
||||
|
||||
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import androidx.annotation.RequiresPermission
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import com.appttude.h_mal.farmr.base.BaseViewModel
|
||||
import com.appttude.h_mal.farmr.data.Repository
|
||||
import com.appttude.h_mal.farmr.data.legacydb.ShiftObject
|
||||
import com.appttude.h_mal.farmr.data.legacydb.ShiftsContract.ShiftsEntry.COLUMN_SHIFT_BREAK
|
||||
@@ -21,24 +18,14 @@ import com.appttude.h_mal.farmr.data.legacydb.ShiftsContract.ShiftsEntry.COLUMN_
|
||||
import com.appttude.h_mal.farmr.data.legacydb.ShiftsContract.ShiftsEntry.COLUMN_SHIFT_TYPE
|
||||
import com.appttude.h_mal.farmr.data.legacydb.ShiftsContract.ShiftsEntry.COLUMN_SHIFT_UNIT
|
||||
import com.appttude.h_mal.farmr.data.legacydb.ShiftsContract.ShiftsEntry._ID
|
||||
import com.appttude.h_mal.farmr.data.prefs.DESCRIPTION
|
||||
import com.appttude.h_mal.farmr.data.prefs.TIME_IN
|
||||
import com.appttude.h_mal.farmr.data.prefs.TIME_OUT
|
||||
import com.appttude.h_mal.farmr.data.prefs.TYPE
|
||||
import com.appttude.h_mal.farmr.model.FilterStore
|
||||
import com.appttude.h_mal.farmr.model.Order
|
||||
import com.appttude.h_mal.farmr.model.Shift
|
||||
import com.appttude.h_mal.farmr.model.ShiftType
|
||||
import com.appttude.h_mal.farmr.model.Sortable
|
||||
import com.appttude.h_mal.farmr.model.Success
|
||||
import com.appttude.h_mal.farmr.utils.CURRENCY
|
||||
import com.appttude.h_mal.farmr.utils.calculateDuration
|
||||
import com.appttude.h_mal.farmr.utils.convertDateString
|
||||
import com.appttude.h_mal.farmr.utils.dateStringIsValid
|
||||
import com.appttude.h_mal.farmr.utils.formatToTwoDp
|
||||
import com.appttude.h_mal.farmr.utils.getTimeString
|
||||
import com.appttude.h_mal.farmr.utils.formatAsCurrencyString
|
||||
import com.appttude.h_mal.farmr.utils.sortedByOrder
|
||||
import com.appttude.h_mal.farmr.utils.timeStringIsValid
|
||||
import jxl.Workbook
|
||||
import jxl.WorkbookSettings
|
||||
import jxl.write.Label
|
||||
@@ -46,25 +33,24 @@ import jxl.write.WritableWorkbook
|
||||
import jxl.write.WriteException
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.Calendar
|
||||
import java.util.Locale
|
||||
|
||||
|
||||
class MainViewModel(
|
||||
private val repository: Repository
|
||||
) : BaseViewModel() {
|
||||
) : ShiftViewModel(repository) {
|
||||
|
||||
private val _shiftLiveData = MutableLiveData<List<ShiftObject>>()
|
||||
val shiftLiveData: LiveData<List<ShiftObject>> = _shiftLiveData
|
||||
private val shiftLiveData: LiveData<List<ShiftObject>> = _shiftLiveData
|
||||
|
||||
private var mSort: Sortable = Sortable.ID
|
||||
private var mOrder: Order = Order.ASCENDING
|
||||
|
||||
private var mFilterStore: FilterStore? = null
|
||||
|
||||
private val observer = Observer<List<ShiftObject>> {
|
||||
val result = it.applyFilters().sortList(mSort, mOrder)
|
||||
onSuccess(result)
|
||||
it?.let {
|
||||
val result = it.applyFilters().sortList(mSort, mOrder)
|
||||
onSuccess(result)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
@@ -148,8 +134,9 @@ class MainViewModel(
|
||||
var countOfTypeP = 0
|
||||
var totalUnits = 0f
|
||||
var totalPay = 0f
|
||||
val lines = _shiftLiveData.value?.size ?: 0
|
||||
_shiftLiveData.value?.forEach {
|
||||
var lines = 0
|
||||
_shiftLiveData.value?.applyFilters()?.forEach {
|
||||
lines += 1
|
||||
totalDuration += it.duration
|
||||
when (ShiftType.getEnumByType(it.type)) {
|
||||
ShiftType.HOURLY -> countOfTypeH += 1
|
||||
@@ -169,161 +156,6 @@ class MainViewModel(
|
||||
)
|
||||
}
|
||||
|
||||
fun getCurrentShift(id: Long) = repository.readSingleShiftFromDatabase(id)
|
||||
|
||||
fun insertHourlyShift(
|
||||
description: String,
|
||||
date: String,
|
||||
rateOfPay: Float,
|
||||
timeIn: String?,
|
||||
timeOut: String?,
|
||||
breakMins: Int?,
|
||||
) {
|
||||
// Validate inputs from the edit texts
|
||||
(description.length > 3).validateField {
|
||||
onError("Description length should be longer")
|
||||
return
|
||||
}
|
||||
date.dateStringIsValid().validateField {
|
||||
onError("Date format is invalid")
|
||||
return
|
||||
}
|
||||
(rateOfPay >= 0.00).validateField {
|
||||
onError("Rate of pay is invalid")
|
||||
return
|
||||
}
|
||||
timeIn?.timeStringIsValid()?.validateField {
|
||||
onError("Time in format is in correct")
|
||||
return
|
||||
}
|
||||
timeOut?.timeStringIsValid()?.validateField {
|
||||
onError("Time out format is in correct")
|
||||
return
|
||||
}
|
||||
breakMins?.let { it > 0 }?.validateField {
|
||||
onError("Break in minutes is invalid")
|
||||
return
|
||||
}
|
||||
|
||||
doTry {
|
||||
val result = insertShiftIntoDatabase(
|
||||
ShiftType.HOURLY,
|
||||
description,
|
||||
date,
|
||||
rateOfPay.formatToTwoDp(),
|
||||
timeIn,
|
||||
timeOut,
|
||||
breakMins,
|
||||
null
|
||||
)
|
||||
|
||||
if (result) onSuccess(Success("Shift successfully added"))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun insertPieceRateShift(
|
||||
description: String,
|
||||
date: String,
|
||||
units: Float,
|
||||
rateOfPay: Float
|
||||
) {
|
||||
// Validate inputs from the edit texts
|
||||
(description.length > 3).validateField {
|
||||
onError("Description length should be longer")
|
||||
return
|
||||
}
|
||||
date.dateStringIsValid().validateField {
|
||||
onError("Date format is invalid")
|
||||
return
|
||||
}
|
||||
(rateOfPay >= 0.00).validateField {
|
||||
onError("Rate of pay is invalid")
|
||||
return
|
||||
}
|
||||
(units.toInt() >= 0).validateField {
|
||||
onError("Units cannot be below zero")
|
||||
return
|
||||
}
|
||||
|
||||
doTry {
|
||||
val result = insertShiftIntoDatabase(
|
||||
type = ShiftType.PIECE,
|
||||
description = description,
|
||||
date = date,
|
||||
rateOfPay = rateOfPay.formatToTwoDp(),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
units = units
|
||||
)
|
||||
if (result) onSuccess(Success("New shift successfully added"))
|
||||
}
|
||||
}
|
||||
|
||||
fun updateShift(
|
||||
id: Long,
|
||||
type: String? = null,
|
||||
description: String? = null,
|
||||
date: String? = null,
|
||||
rateOfPay: Float? = null,
|
||||
timeIn: String? = null,
|
||||
timeOut: String? = null,
|
||||
breakMins: Int? = null,
|
||||
units: Float? = null,
|
||||
) {
|
||||
description?.let {
|
||||
(it.length > 3).validateField {
|
||||
onError("Description length should be longer")
|
||||
return
|
||||
}
|
||||
}
|
||||
date?.dateStringIsValid()?.validateField {
|
||||
onError("Date format is invalid")
|
||||
return
|
||||
}
|
||||
rateOfPay?.let {
|
||||
(it >= 0.00).validateField {
|
||||
onError("Rate of pay is invalid")
|
||||
return
|
||||
}
|
||||
}
|
||||
units?.let {
|
||||
(it.toInt() >= 0).validateField {
|
||||
onError("Units cannot be below zero")
|
||||
return
|
||||
}
|
||||
}
|
||||
timeIn?.timeStringIsValid()?.validateField {
|
||||
onError("Time in format is in correct")
|
||||
return
|
||||
}
|
||||
timeOut?.timeStringIsValid()?.validateField {
|
||||
onError("Time out format is in correct")
|
||||
return
|
||||
}
|
||||
breakMins?.let { it >= 0 }?.validateField {
|
||||
onError("Break in minutes is invalid")
|
||||
return
|
||||
}
|
||||
|
||||
doTry {
|
||||
val result = updateShiftInDatabase(
|
||||
id,
|
||||
type = type?.let { ShiftType.getEnumByType(it) },
|
||||
description = description,
|
||||
date = date,
|
||||
rateOfPay = rateOfPay,
|
||||
timeIn = timeIn,
|
||||
timeOut = timeOut,
|
||||
breakMins = breakMins,
|
||||
units = units
|
||||
)
|
||||
|
||||
if (result) onSuccess(Success("Shift successfully updated"))
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteShift(id: Long) {
|
||||
if (!repository.deleteSingleShiftFromDatabase(id)) {
|
||||
onError("Failed to delete shift")
|
||||
@@ -340,134 +172,6 @@ class MainViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateShiftInDatabase(
|
||||
id: Long,
|
||||
type: ShiftType? = null,
|
||||
description: String? = null,
|
||||
date: String? = null,
|
||||
rateOfPay: Float? = null,
|
||||
timeIn: String? = null,
|
||||
timeOut: String? = null,
|
||||
breakMins: Int? = null,
|
||||
units: Float? = null,
|
||||
): Boolean {
|
||||
val currentShift = repository.readSingleShiftFromDatabase(id)?.copyToShift()
|
||||
?: throw IOException("Cannot update shift as it does not exist")
|
||||
|
||||
val shift = when (type) {
|
||||
ShiftType.HOURLY -> {
|
||||
// Shift type has changed so mandatory fields for hourly shift are now required as well
|
||||
val insertTimeIn =
|
||||
(timeIn ?: currentShift.timeIn) ?: throw IOException("No time in inserted")
|
||||
val insertTimeOut =
|
||||
(timeOut ?: currentShift.timeOut) ?: throw IOException("No time out inserted")
|
||||
Shift(
|
||||
description = description ?: currentShift.description,
|
||||
date = date ?: currentShift.date,
|
||||
timeIn = insertTimeIn,
|
||||
timeOut = insertTimeOut,
|
||||
breakMins = breakMins ?: currentShift.breakMins,
|
||||
rateOfPay = rateOfPay ?: currentShift.rateOfPay
|
||||
)
|
||||
}
|
||||
|
||||
ShiftType.PIECE -> {
|
||||
// Shift type has changed so mandatory fields for piece rate shift are now required as well
|
||||
val insertUnits = (units ?: currentShift.units)
|
||||
?: throw IOException("Units must be inserted for piece rate shifts")
|
||||
Shift(
|
||||
description = description ?: currentShift.description,
|
||||
date = date ?: currentShift.date,
|
||||
units = insertUnits,
|
||||
rateOfPay = rateOfPay ?: currentShift.rateOfPay
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
if (timeIn == null && timeOut == null && units == null && breakMins == null && rateOfPay == null) {
|
||||
// Updates to description or date field
|
||||
currentShift.copy(
|
||||
description = description ?: currentShift.description,
|
||||
date = date ?: currentShift.date,
|
||||
)
|
||||
} else {
|
||||
// Updating shifts where shift type has remained the same
|
||||
when (currentShift.type) {
|
||||
ShiftType.HOURLY -> {
|
||||
val insertTimeIn = (timeIn ?: currentShift.timeIn) ?: throw IOException(
|
||||
"No time in inserted"
|
||||
)
|
||||
val insertTimeOut = (timeOut ?: currentShift.timeOut)
|
||||
?: throw IOException("No time out inserted")
|
||||
Shift(
|
||||
description = description ?: currentShift.description,
|
||||
date = date ?: currentShift.date,
|
||||
timeIn = insertTimeIn,
|
||||
timeOut = insertTimeOut,
|
||||
breakMins = breakMins ?: currentShift.breakMins,
|
||||
rateOfPay = rateOfPay ?: currentShift.rateOfPay
|
||||
)
|
||||
}
|
||||
|
||||
ShiftType.PIECE -> {
|
||||
val insertUnits = (units ?: currentShift.units)
|
||||
?: throw IOException("Units must be inserted for piece rate shifts")
|
||||
Shift(
|
||||
description = description ?: currentShift.description,
|
||||
date = date ?: currentShift.date,
|
||||
units = insertUnits,
|
||||
rateOfPay = rateOfPay ?: currentShift.rateOfPay
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return repository.updateShiftIntoDatabase(id, shift)
|
||||
}
|
||||
|
||||
private fun insertShiftIntoDatabase(
|
||||
type: ShiftType,
|
||||
description: String,
|
||||
date: String,
|
||||
rateOfPay: Float,
|
||||
timeIn: String?,
|
||||
timeOut: String?,
|
||||
breakMins: Int?,
|
||||
units: Float?,
|
||||
): Boolean {
|
||||
val shift = when (type) {
|
||||
ShiftType.HOURLY -> {
|
||||
if (timeIn.isNullOrBlank() && timeOut.isNullOrBlank()) throw IOException("Time in and time out are null")
|
||||
val calendar by lazy { Calendar.getInstance() }
|
||||
val insertTimeIn = timeIn ?: calendar.getTimeString()
|
||||
val insertTimeOut = timeOut ?: calendar.getTimeString()
|
||||
|
||||
Shift(
|
||||
description = description,
|
||||
date = date,
|
||||
timeIn = insertTimeIn,
|
||||
timeOut = insertTimeOut,
|
||||
breakMins = breakMins,
|
||||
rateOfPay = rateOfPay
|
||||
)
|
||||
}
|
||||
|
||||
ShiftType.PIECE -> {
|
||||
Shift(
|
||||
description = description,
|
||||
date = date,
|
||||
units = units!!,
|
||||
rateOfPay = rateOfPay,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return repository.insertShiftIntoDatabase(shift)
|
||||
}
|
||||
|
||||
|
||||
private fun buildInfoString(
|
||||
totalDuration: Float,
|
||||
countOfHourly: Int,
|
||||
@@ -488,63 +192,21 @@ class MainViewModel(
|
||||
stringBuilder.append("Total Units: ").append(totalUnits).append("\n")
|
||||
}
|
||||
if (totalPay != 0f) {
|
||||
stringBuilder.append("Total Pay: ").append(CURRENCY).append(totalPay).append("\n")
|
||||
stringBuilder.append("Total Pay: ").append(totalPay.formatAsCurrencyString())
|
||||
}
|
||||
return stringBuilder.toString()
|
||||
}
|
||||
|
||||
fun refreshLiveData() {
|
||||
_shiftLiveData.postValue(repository.readShiftsFromDatabase())
|
||||
repository.readShiftsFromDatabase()?.let { _shiftLiveData.postValue(it) }
|
||||
}
|
||||
|
||||
private inline fun Boolean.validateField(failureCallback: () -> Unit) {
|
||||
if (!this) failureCallback.invoke()
|
||||
}
|
||||
|
||||
/**
|
||||
* Lambda function that will invoke onError(...) on failure
|
||||
* but update live data when successful
|
||||
*/
|
||||
private inline fun doTry(operation: () -> Unit) {
|
||||
try {
|
||||
operation.invoke()
|
||||
refreshLiveData()
|
||||
} catch (e: Exception) {
|
||||
onError(e)
|
||||
}
|
||||
}
|
||||
|
||||
fun setFiltrationDetails(
|
||||
description: String?,
|
||||
dateFrom: String?,
|
||||
dateTo: String?,
|
||||
type: String?
|
||||
) {
|
||||
repository.setFilteringDetailsInPrefs(description, dateFrom, dateTo, type)
|
||||
onSuccess(Success("Filter(s) successfully applied"))
|
||||
fun clearFilters() {
|
||||
super.setFiltrationDetails(null, null, null, null)
|
||||
onSuccess(Success("Filters have been cleared"))
|
||||
refreshLiveData()
|
||||
}
|
||||
|
||||
fun getFiltrationDetails(): FilterStore {
|
||||
val prefs = repository.retrieveFilteringDetailsInPrefs()
|
||||
mFilterStore = FilterStore(
|
||||
prefs[DESCRIPTION],
|
||||
prefs[TIME_IN],
|
||||
prefs[TIME_OUT],
|
||||
prefs[TYPE]
|
||||
)
|
||||
return mFilterStore!!
|
||||
}
|
||||
|
||||
fun retrieveDurationText(mTimeIn: String?, mTimeOut: String?, mBreaks: Int?): Float? {
|
||||
try {
|
||||
return calculateDuration(mTimeIn, mTimeOut, mBreaks)
|
||||
} catch (e: IOException) {
|
||||
onError(e)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@RequiresPermission(WRITE_EXTERNAL_STORAGE)
|
||||
fun createExcelSheet(file: File): File? {
|
||||
val wbSettings = WorkbookSettings().apply {
|
||||
@@ -574,7 +236,8 @@ class MainViewModel(
|
||||
return null
|
||||
}
|
||||
val sortAndOrder = getSortAndOrder()
|
||||
val data = shiftLiveData.value!!.applyFilters().sortList(sortAndOrder.first, sortAndOrder.second)
|
||||
val data = shiftLiveData.value!!.applyFilters()
|
||||
.sortList(sortAndOrder.first, sortAndOrder.second)
|
||||
var currentRow = 0
|
||||
val cells = data.mapIndexed { index, shift ->
|
||||
currentRow += 1
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.appttude.h_mal.farmr.viewmodel
|
||||
|
||||
import com.appttude.h_mal.farmr.base.BaseViewModel
|
||||
import com.appttude.h_mal.farmr.data.Repository
|
||||
import com.appttude.h_mal.farmr.data.prefs.DESCRIPTION
|
||||
import com.appttude.h_mal.farmr.data.prefs.DATE_IN
|
||||
import com.appttude.h_mal.farmr.data.prefs.DATE_OUT
|
||||
import com.appttude.h_mal.farmr.data.prefs.TYPE
|
||||
import com.appttude.h_mal.farmr.model.FilterStore
|
||||
|
||||
|
||||
open class ShiftViewModel(
|
||||
private val repository: Repository
|
||||
) : BaseViewModel() {
|
||||
|
||||
/*
|
||||
* Add Item & Further info
|
||||
*/
|
||||
fun getCurrentShift(id: Long) = repository.readSingleShiftFromDatabase(id)
|
||||
|
||||
/**
|
||||
* Lambda function that will invoke onError(...) on failure
|
||||
* but update live data when successful
|
||||
*/
|
||||
private inline fun doTry(operation: () -> Unit) {
|
||||
try {
|
||||
operation.invoke()
|
||||
} catch (e: Exception) {
|
||||
onError(e)
|
||||
}
|
||||
}
|
||||
|
||||
open fun setFiltrationDetails(
|
||||
description: String?,
|
||||
dateFrom: String?,
|
||||
dateTo: String?,
|
||||
type: String?
|
||||
) {
|
||||
repository.setFilteringDetailsInPrefs(description, dateFrom, dateTo, type)
|
||||
}
|
||||
|
||||
open fun getFiltrationDetails(): FilterStore {
|
||||
val prefs = repository.retrieveFilteringDetailsInPrefs()
|
||||
return FilterStore(
|
||||
prefs[DESCRIPTION],
|
||||
prefs[DATE_IN],
|
||||
prefs[DATE_OUT],
|
||||
prefs[TYPE]
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,308 @@
|
||||
package com.appttude.h_mal.farmr.viewmodel
|
||||
|
||||
import com.appttude.h_mal.farmr.data.Repository
|
||||
import com.appttude.h_mal.farmr.model.Shift
|
||||
import com.appttude.h_mal.farmr.model.ShiftType
|
||||
import com.appttude.h_mal.farmr.model.Success
|
||||
import com.appttude.h_mal.farmr.utils.calculateDuration
|
||||
import com.appttude.h_mal.farmr.utils.dateStringIsValid
|
||||
import com.appttude.h_mal.farmr.utils.formatToTwoDp
|
||||
import com.appttude.h_mal.farmr.utils.getTimeString
|
||||
import com.appttude.h_mal.farmr.utils.timeStringIsValid
|
||||
import java.io.IOException
|
||||
import java.util.Calendar
|
||||
|
||||
|
||||
class SubmissionViewModel(
|
||||
private val repository: Repository
|
||||
) : ShiftViewModel(repository) {
|
||||
|
||||
fun insertHourlyShift(
|
||||
description: String,
|
||||
date: String,
|
||||
rateOfPay: Float,
|
||||
timeIn: String?,
|
||||
timeOut: String?,
|
||||
breakMins: Int?,
|
||||
) {
|
||||
// Validate inputs from the edit texts
|
||||
(description.length > 3).validateField {
|
||||
onError("Description length should be longer")
|
||||
return
|
||||
}
|
||||
date.dateStringIsValid().validateField {
|
||||
onError("Date format is invalid")
|
||||
return
|
||||
}
|
||||
(rateOfPay >= 0.00).validateField {
|
||||
onError("Rate of pay is invalid")
|
||||
return
|
||||
}
|
||||
timeIn?.timeStringIsValid()?.validateField {
|
||||
onError("Time in format is in correct")
|
||||
return
|
||||
}
|
||||
timeOut?.timeStringIsValid()?.validateField {
|
||||
onError("Time out format is in correct")
|
||||
return
|
||||
}
|
||||
breakMins?.let { it >= 0 }?.validateField {
|
||||
onError("Break in minutes is invalid")
|
||||
return
|
||||
}
|
||||
|
||||
val result = insertShiftIntoDatabase(
|
||||
ShiftType.HOURLY,
|
||||
description,
|
||||
date,
|
||||
rateOfPay.formatToTwoDp(),
|
||||
timeIn,
|
||||
timeOut,
|
||||
breakMins,
|
||||
null
|
||||
)
|
||||
|
||||
if (result) onSuccess(Success("New shift successfully added"))
|
||||
else onError("Cannot insert shift")
|
||||
}
|
||||
|
||||
fun insertPieceRateShift(
|
||||
description: String,
|
||||
date: String,
|
||||
units: Float,
|
||||
rateOfPay: Float
|
||||
) {
|
||||
// Validate inputs from the edit texts
|
||||
(description.length > 3).validateField {
|
||||
onError("Description length should be longer")
|
||||
return
|
||||
}
|
||||
date.dateStringIsValid().validateField {
|
||||
onError("Date format is invalid")
|
||||
return
|
||||
}
|
||||
(rateOfPay >= 0.00).validateField {
|
||||
onError("Rate of pay is invalid")
|
||||
return
|
||||
}
|
||||
(units.toInt() >= 0).validateField {
|
||||
onError("Units cannot be below zero")
|
||||
return
|
||||
}
|
||||
|
||||
val result = insertShiftIntoDatabase(
|
||||
type = ShiftType.PIECE,
|
||||
description = description,
|
||||
date = date,
|
||||
rateOfPay = rateOfPay.formatToTwoDp(),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
units = units
|
||||
)
|
||||
if (result) onSuccess(Success("New shift successfully added"))
|
||||
else onError("Cannot insert shift")
|
||||
}
|
||||
|
||||
fun updateShift(
|
||||
id: Long,
|
||||
type: String? = null,
|
||||
description: String? = null,
|
||||
date: String? = null,
|
||||
rateOfPay: Float? = null,
|
||||
timeIn: String? = null,
|
||||
timeOut: String? = null,
|
||||
breakMins: Int? = null,
|
||||
units: Float? = null,
|
||||
) {
|
||||
description?.let {
|
||||
(it.length > 3).validateField {
|
||||
onError("Description length should be longer")
|
||||
return
|
||||
}
|
||||
}
|
||||
date?.dateStringIsValid()?.validateField {
|
||||
onError("Date format is invalid")
|
||||
return
|
||||
}
|
||||
rateOfPay?.let {
|
||||
(it >= 0.00).validateField {
|
||||
onError("Rate of pay is invalid")
|
||||
return
|
||||
}
|
||||
}
|
||||
units?.let {
|
||||
(it.toInt() >= 0).validateField {
|
||||
onError("Units cannot be below zero")
|
||||
return
|
||||
}
|
||||
}
|
||||
timeIn?.timeStringIsValid()?.validateField {
|
||||
onError("Time in format is in correct")
|
||||
return
|
||||
}
|
||||
timeOut?.timeStringIsValid()?.validateField {
|
||||
onError("Time out format is in correct")
|
||||
return
|
||||
}
|
||||
breakMins?.let { it >= 0 }?.validateField {
|
||||
onError("Break in minutes is invalid")
|
||||
return
|
||||
}
|
||||
|
||||
val result = updateShiftInDatabase(
|
||||
id,
|
||||
type = type?.let { ShiftType.getEnumByType(it) },
|
||||
description = description,
|
||||
date = date,
|
||||
rateOfPay = rateOfPay,
|
||||
timeIn = timeIn,
|
||||
timeOut = timeOut,
|
||||
breakMins = breakMins,
|
||||
units = units
|
||||
)
|
||||
|
||||
if (result) onSuccess(Success("Shift successfully updated"))
|
||||
else onError("Cannot update shift")
|
||||
}
|
||||
|
||||
private fun updateShiftInDatabase(
|
||||
id: Long,
|
||||
type: ShiftType? = null,
|
||||
description: String? = null,
|
||||
date: String? = null,
|
||||
rateOfPay: Float? = null,
|
||||
timeIn: String? = null,
|
||||
timeOut: String? = null,
|
||||
breakMins: Int? = null,
|
||||
units: Float? = null,
|
||||
): Boolean {
|
||||
val currentShift = repository.readSingleShiftFromDatabase(id)?.copyToShift()
|
||||
?: throw IOException("Cannot update shift as it does not exist")
|
||||
|
||||
val shift = when (type) {
|
||||
ShiftType.HOURLY -> {
|
||||
// Shift type has changed so mandatory fields for hourly shift are now required as well
|
||||
val insertTimeIn =
|
||||
(timeIn ?: currentShift.timeIn) ?: throw IOException("No time in inserted")
|
||||
val insertTimeOut =
|
||||
(timeOut ?: currentShift.timeOut) ?: throw IOException("No time out inserted")
|
||||
Shift(
|
||||
description = description ?: currentShift.description,
|
||||
date = date ?: currentShift.date,
|
||||
timeIn = insertTimeIn,
|
||||
timeOut = insertTimeOut,
|
||||
breakMins = breakMins ?: currentShift.breakMins,
|
||||
rateOfPay = rateOfPay ?: currentShift.rateOfPay
|
||||
)
|
||||
}
|
||||
|
||||
ShiftType.PIECE -> {
|
||||
// Shift type has changed so mandatory fields for piece rate shift are now required as well
|
||||
val insertUnits = (units ?: currentShift.units)
|
||||
?: throw IOException("Units must be inserted for piece rate shifts")
|
||||
Shift(
|
||||
description = description ?: currentShift.description,
|
||||
date = date ?: currentShift.date,
|
||||
units = insertUnits,
|
||||
rateOfPay = rateOfPay ?: currentShift.rateOfPay
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
if (timeIn == null && timeOut == null && units == null && breakMins == null && rateOfPay == null) {
|
||||
// Updates to description or date field
|
||||
currentShift.copy(
|
||||
description = description ?: currentShift.description,
|
||||
date = date ?: currentShift.date,
|
||||
)
|
||||
} else {
|
||||
// Updating shifts where shift type has remained the same
|
||||
when (currentShift.type) {
|
||||
ShiftType.HOURLY -> {
|
||||
val insertTimeIn = (timeIn ?: currentShift.timeIn) ?: throw IOException(
|
||||
"No time in inserted"
|
||||
)
|
||||
val insertTimeOut = (timeOut ?: currentShift.timeOut)
|
||||
?: throw IOException("No time out inserted")
|
||||
Shift(
|
||||
description = description ?: currentShift.description,
|
||||
date = date ?: currentShift.date,
|
||||
timeIn = insertTimeIn,
|
||||
timeOut = insertTimeOut,
|
||||
breakMins = breakMins ?: currentShift.breakMins,
|
||||
rateOfPay = rateOfPay ?: currentShift.rateOfPay
|
||||
)
|
||||
}
|
||||
|
||||
ShiftType.PIECE -> {
|
||||
val insertUnits = (units ?: currentShift.units)
|
||||
?: throw IOException("Units must be inserted for piece rate shifts")
|
||||
Shift(
|
||||
description = description ?: currentShift.description,
|
||||
date = date ?: currentShift.date,
|
||||
units = insertUnits,
|
||||
rateOfPay = rateOfPay ?: currentShift.rateOfPay
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return repository.updateShiftIntoDatabase(id, shift)
|
||||
}
|
||||
|
||||
private fun insertShiftIntoDatabase(
|
||||
type: ShiftType,
|
||||
description: String,
|
||||
date: String,
|
||||
rateOfPay: Float,
|
||||
timeIn: String?,
|
||||
timeOut: String?,
|
||||
breakMins: Int?,
|
||||
units: Float?,
|
||||
): Boolean {
|
||||
val shift = when (type) {
|
||||
ShiftType.HOURLY -> {
|
||||
if (timeIn.isNullOrBlank() && timeOut.isNullOrBlank()) throw IOException("Time in and time out are null")
|
||||
val calendar by lazy { Calendar.getInstance() }
|
||||
val insertTimeIn = timeIn ?: calendar.getTimeString()
|
||||
val insertTimeOut = timeOut ?: calendar.getTimeString()
|
||||
Shift(
|
||||
description = description,
|
||||
date = date,
|
||||
timeIn = insertTimeIn,
|
||||
timeOut = insertTimeOut,
|
||||
breakMins = breakMins,
|
||||
rateOfPay = rateOfPay
|
||||
)
|
||||
}
|
||||
|
||||
ShiftType.PIECE -> {
|
||||
Shift(
|
||||
description = description,
|
||||
date = date,
|
||||
units = units!!,
|
||||
rateOfPay = rateOfPay,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return repository.insertShiftIntoDatabase(shift)
|
||||
}
|
||||
|
||||
private inline fun Boolean.validateField(failureCallback: () -> Unit) {
|
||||
if (!this) failureCallback.invoke()
|
||||
}
|
||||
|
||||
fun retrieveDurationText(mTimeIn: String?, mTimeOut: String?, mBreaks: Int?): Float? {
|
||||
try {
|
||||
return calculateDuration(mTimeIn, mTimeOut, mBreaks)
|
||||
} catch (e: IOException) {
|
||||
onError(e)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user