mirror of
https://github.com/hmalik144/Farmr.git
synced 2026-01-31 02:41:49 +00:00
- MVVM refactor
- Kodein DI added - Overhaul dirty code in views - Bug fixes
This commit is contained in:
@@ -53,6 +53,6 @@ abstract class BaseActivity<V : BaseViewModel> : AppCompatActivity(), KodeinAwar
|
||||
}
|
||||
|
||||
fun setTitleInActionBar(title: String) {
|
||||
setTitle(title)
|
||||
supportActionBar?.title = title
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.appttude.h_mal.farmr.data.legacydb
|
||||
|
||||
import android.content.ContentResolver
|
||||
import android.content.ContentUris
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
@@ -20,8 +21,7 @@ import com.appttude.h_mal.farmr.data.legacydb.ShiftsContract.ShiftsEntry._ID
|
||||
import com.appttude.h_mal.farmr.model.Shift
|
||||
import com.appttude.h_mal.farmr.model.ShiftType
|
||||
|
||||
class LegacyDatabase(context: Context) {
|
||||
private val resolver = context.contentResolver
|
||||
class LegacyDatabase(private val resolver: ContentResolver) {
|
||||
|
||||
private val projection = arrayOf<String?>(
|
||||
_ID,
|
||||
@@ -44,7 +44,7 @@ class LegacyDatabase(context: Context) {
|
||||
val values = ContentValues().apply {
|
||||
put(COLUMN_SHIFT_TYPE, shift.type.type)
|
||||
put(COLUMN_SHIFT_DESCRIPTION, shift.description)
|
||||
put(COLUMN_SHIFT_DATE, shift.description)
|
||||
put(COLUMN_SHIFT_DATE, shift.date)
|
||||
put(COLUMN_SHIFT_TIME_IN, shift.timeIn ?: "00:00")
|
||||
put(COLUMN_SHIFT_TIME_OUT, shift.timeOut ?: "00:00")
|
||||
put(COLUMN_SHIFT_DURATION, shift.duration ?: 0.00f)
|
||||
@@ -63,8 +63,9 @@ class LegacyDatabase(context: Context) {
|
||||
projection,
|
||||
null, null, null
|
||||
) ?: return null
|
||||
cursor.moveToFirst()
|
||||
val shifts = (0..cursor.count).map { cursor.getShift() }
|
||||
val shifts = generateSequence { if (cursor.moveToNext()) cursor else null }
|
||||
.map { it.getShift() }
|
||||
.toList()
|
||||
// close cursor after query operations
|
||||
cursor.close()
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ class ShiftApplication: Application(), KodeinAware {
|
||||
override val kodein = Kodein.lazy {
|
||||
import(androidXModule(this@ShiftApplication))
|
||||
|
||||
bind() from singleton { LegacyDatabase(this@ShiftApplication) }
|
||||
bind() from singleton { LegacyDatabase(contentResolver) }
|
||||
bind() from singleton { PreferenceProvider(this@ShiftApplication) }
|
||||
bind() from singleton { RepositoryImpl(instance(), instance()) }
|
||||
|
||||
|
||||
@@ -51,11 +51,13 @@ class FragmentAddItem : BaseFragment<MainViewModel>(R.layout.fragment_add_item),
|
||||
private var mDescription: String? = null
|
||||
private var mTimeIn: String? = null
|
||||
private var mTimeOut: String? = null
|
||||
private var mBreaks = 0
|
||||
private var mUnits = 0f
|
||||
private var mBreaks: Int? = null
|
||||
private var mUnits: Float? = null
|
||||
private var mPayRate = 0f
|
||||
private var mType: ShiftType? = null
|
||||
private var mDuration: Float = 0f
|
||||
private var mDuration: Float? = null
|
||||
|
||||
private var id: Long? = null
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
@@ -97,7 +99,7 @@ class FragmentAddItem : BaseFragment<MainViewModel>(R.layout.fragment_add_item),
|
||||
calculateTotalPay()
|
||||
}
|
||||
mUnitEditText.doAfterTextChanged {
|
||||
it.toString().toFloatOrNull()?.let { u -> mPayRate = u }
|
||||
it.toString().toFloatOrNull()?.let { u -> mUnits = u }
|
||||
calculateTotalPay()
|
||||
}
|
||||
mPayRateEditText.doAfterTextChanged {
|
||||
@@ -113,6 +115,8 @@ class FragmentAddItem : BaseFragment<MainViewModel>(R.layout.fragment_add_item),
|
||||
}
|
||||
|
||||
private fun setupViewAfterViewCreated() {
|
||||
id = arguments?.getLong(ID)
|
||||
|
||||
val title = when (arguments?.containsKey(ID)) {
|
||||
true -> {
|
||||
// Since we are editing a shift lets load the shift data into the views
|
||||
@@ -158,6 +162,7 @@ class FragmentAddItem : BaseFragment<MainViewModel>(R.layout.fragment_add_item),
|
||||
hourlyDataView.show()
|
||||
durationHolder.show()
|
||||
}
|
||||
|
||||
R.id.piecerate -> {
|
||||
mType = ShiftType.PIECE
|
||||
wholeView.show()
|
||||
@@ -169,27 +174,62 @@ class FragmentAddItem : BaseFragment<MainViewModel>(R.layout.fragment_add_item),
|
||||
}
|
||||
|
||||
private fun submitShift() {
|
||||
mDate.validateField({ !it.isNullOrBlank() }){
|
||||
mDate.validateField({ !it.isNullOrBlank() }) {
|
||||
onFailure("Date field cannot be empty")
|
||||
return
|
||||
}
|
||||
mDescription.validateField({ !it.isNullOrBlank() }){
|
||||
mDescription.validateField({ !it.isNullOrBlank() }) {
|
||||
onFailure("Description field cannot be empty")
|
||||
return
|
||||
}
|
||||
mPayRate.validateField({ !it.isNaN() }){
|
||||
mPayRate.validateField({ !it.isNaN() }) {
|
||||
onFailure("Rate of pay field cannot be empty")
|
||||
return
|
||||
}
|
||||
|
||||
if (mPieceRadioButton.isChecked) {
|
||||
mUnits.validateField({!it.isNaN()}) {
|
||||
|
||||
mUnits.validateField({ it != null && it >= 0 }) {
|
||||
onFailure("Units field cannot be empty")
|
||||
return
|
||||
}
|
||||
viewModel.insertPieceRateShift(mDescription!!, mDate!!, mUnits, mPayRate)
|
||||
if (id != null) {
|
||||
// update
|
||||
viewModel.updateShift(
|
||||
id!!,
|
||||
description = mDescription,
|
||||
date = mDate,
|
||||
units = mUnits,
|
||||
rateOfPay = mPayRate
|
||||
)
|
||||
} else {
|
||||
// insert
|
||||
viewModel.insertPieceRateShift(mDescription!!, mDate!!, mUnits!!, mPayRate)
|
||||
}
|
||||
} else if (mHourlyRadioButton.isChecked) {
|
||||
viewModel.insertHourlyShift(mDescription!!, mDate!!, mPayRate, mTimeIn, mTimeOut, mBreaks)
|
||||
if (id != null) {
|
||||
// update
|
||||
viewModel.updateShift(
|
||||
id!!,
|
||||
description = mDescription,
|
||||
date = mDate,
|
||||
rateOfPay = mPayRate,
|
||||
timeIn = mTimeIn,
|
||||
timeOut = mTimeOut,
|
||||
breakMins = mBreaks
|
||||
)
|
||||
} else {
|
||||
// insert
|
||||
viewModel.insertHourlyShift(
|
||||
mDescription!!,
|
||||
mDate!!,
|
||||
mPayRate,
|
||||
mTimeIn,
|
||||
mTimeOut,
|
||||
mBreaks
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,11 +239,13 @@ class FragmentAddItem : BaseFragment<MainViewModel>(R.layout.fragment_add_item),
|
||||
ShiftType.HOURLY -> {
|
||||
// Calculate duration before total pay calculation
|
||||
mDuration = viewModel.retrieveDurationText(mTimeIn, mTimeOut, mBreaks) ?: return
|
||||
mDurationTextView.text = StringBuilder().append(mDuration).append(" hours").toString()
|
||||
mDuration * mPayRate
|
||||
mDurationTextView.text =
|
||||
StringBuilder().append(mDuration).append(" hours").toString()
|
||||
mDuration!! * mPayRate
|
||||
}
|
||||
|
||||
ShiftType.PIECE -> {
|
||||
mUnits * mPayRate
|
||||
(mUnits ?: 0f) * mPayRate
|
||||
}
|
||||
}
|
||||
mTotalPayTextView.text = total.formatToTwoDpString()
|
||||
|
||||
@@ -27,7 +27,7 @@ import kotlin.system.exitProcess
|
||||
class FragmentMain : BaseFragment<MainViewModel>(R.layout.fragment_main), BackPressedListener {
|
||||
lateinit var activity: MainActivity
|
||||
private lateinit var productListView: RecyclerView
|
||||
private lateinit var mAdapter: ShiftRecyclerAdapter
|
||||
private lateinit var mAdapter: ShiftListAdapter
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -38,7 +38,7 @@ class FragmentMain : BaseFragment<MainViewModel>(R.layout.fragment_main), BackPr
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
mAdapter = ShiftRecyclerAdapter(this) {
|
||||
mAdapter = ShiftListAdapter(this) {
|
||||
viewModel.deleteShift(it)
|
||||
}
|
||||
productListView = view.findViewById(R.id.list_item_view)
|
||||
@@ -49,10 +49,16 @@ class FragmentMain : BaseFragment<MainViewModel>(R.layout.fragment_main), BackPr
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
|
||||
viewModel.refreshLiveData()
|
||||
}
|
||||
|
||||
override fun onSuccess(data: Any?) {
|
||||
super.onSuccess(data)
|
||||
if (data is List<*>) {
|
||||
mAdapter.updateData(data as List<ShiftObject>)
|
||||
mAdapter.submitList(data as List<ShiftObject>)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,10 +22,6 @@ import kotlin.system.exitProcess
|
||||
class MainActivity : BaseActivity<MainViewModel>() {
|
||||
private lateinit var toolbar: Toolbar
|
||||
|
||||
var selection: String? = null
|
||||
var args: Array<String>? = null
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.main_view)
|
||||
@@ -57,11 +53,6 @@ class MainActivity : BaseActivity<MainViewModel>() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun setActionBarTitle(title: String?) {
|
||||
toolbar.title = title
|
||||
}
|
||||
|
||||
// Storage Permissions
|
||||
private val REQUEST_EXTERNAL_STORAGE = 1
|
||||
private val PERMISSIONS_STORAGE = arrayOf(
|
||||
|
||||
@@ -2,26 +2,36 @@ package com.appttude.h_mal.farmr.ui
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import com.appttude.h_mal.farmr.R
|
||||
import com.appttude.h_mal.farmr.base.BaseRecyclerAdapter
|
||||
import com.appttude.h_mal.farmr.data.legacydb.ShiftObject
|
||||
import com.appttude.h_mal.farmr.model.ShiftType
|
||||
import com.appttude.h_mal.farmr.utils.ID
|
||||
import com.appttude.h_mal.farmr.utils.generateView
|
||||
import com.appttude.h_mal.farmr.utils.navigateToFragment
|
||||
|
||||
class ShiftRecyclerAdapter(
|
||||
class ShiftListAdapter(
|
||||
private val fragment: Fragment,
|
||||
private val longPressCallback: (Long) -> Unit
|
||||
) : BaseRecyclerAdapter<ShiftObject>(
|
||||
emptyViewId = R.layout.empty_list_view,
|
||||
currentViewId = R.layout.list_item_1
|
||||
) {
|
||||
override fun bindCurrentView(view: View, position: Int, data: ShiftObject) {
|
||||
) : ListAdapter<ShiftObject, BaseRecyclerAdapter.CurrentViewHolder>(diffCallBack) {
|
||||
override fun onCreateViewHolder(
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
): BaseRecyclerAdapter.CurrentViewHolder {
|
||||
val currentViewHolder = parent.generateView(R.layout.list_item_1)
|
||||
return BaseRecyclerAdapter.CurrentViewHolder(currentViewHolder)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: BaseRecyclerAdapter.CurrentViewHolder, position: Int) {
|
||||
val view = holder.itemView
|
||||
val data = getItem(position)
|
||||
|
||||
val descriptionTextView: TextView = view.findViewById(R.id.location)
|
||||
val dateTextView: TextView = view.findViewById(R.id.date)
|
||||
val totalPay: TextView = view.findViewById(R.id.total_pay)
|
||||
@@ -89,16 +99,15 @@ class ShiftRecyclerAdapter(
|
||||
}
|
||||
}
|
||||
|
||||
// override fun getItemId(position: Int): Long {
|
||||
// return if (list.isNullOrEmpty()) {
|
||||
// RecyclerView.NO_ID
|
||||
// } else {
|
||||
// list!![position].id
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// override fun setHasStableIds(hasStableIds: Boolean) {
|
||||
// super.setHasStableIds(true)
|
||||
// }
|
||||
companion object {
|
||||
val diffCallBack = object : DiffUtil.ItemCallback<ShiftObject>() {
|
||||
override fun areItemsTheSame(oldItem: ShiftObject, newItem: ShiftObject): Boolean {
|
||||
return oldItem.id == newItem.id
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: ShiftObject, newItem: ShiftObject): Boolean {
|
||||
return oldItem == newItem
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,11 +20,11 @@ fun Float.formatToTwoDpString(): String {
|
||||
}
|
||||
|
||||
fun String.dateStringIsValid(): Boolean {
|
||||
return DATE_FORMAT.toPattern().matcher(this).matches()
|
||||
return "([0-9]{4})-([0-9]{2})-([0-9]{2})".toPattern().matcher(this).matches()
|
||||
}
|
||||
|
||||
fun String.timeStringIsValid(): Boolean {
|
||||
return TIME_FORMAT.toPattern().matcher(this).matches()
|
||||
return "^([0-1]?[0-9]|2[0-3]):[0-5][0-9]\$".toPattern().matcher(this).matches()
|
||||
}
|
||||
|
||||
fun Calendar.getTimeString(): String {
|
||||
|
||||
@@ -173,5 +173,7 @@ fun EditText.setDatePicker(onSelected: (String) -> Unit) {
|
||||
}, mYear, mMonth, mDay
|
||||
)
|
||||
mDatePicker.setTitle("Select date")
|
||||
mDatePicker.show()
|
||||
setOnClickListener {
|
||||
mDatePicker.show()
|
||||
}
|
||||
}
|
||||
@@ -160,7 +160,7 @@ class MainViewModel(
|
||||
rateOfPay: Float
|
||||
) {
|
||||
// Validate inputs from the edit texts
|
||||
(description.length < 3).validateField {
|
||||
(description.length > 3).validateField {
|
||||
onError("Description length should be longer")
|
||||
return
|
||||
}
|
||||
@@ -196,11 +196,11 @@ class MainViewModel(
|
||||
type: String? = null,
|
||||
description: String? = null,
|
||||
date: String? = null,
|
||||
rateOfPay: String? = null,
|
||||
rateOfPay: Float? = null,
|
||||
timeIn: String? = null,
|
||||
timeOut: String? = null,
|
||||
breakMins: String? = null,
|
||||
units: String? = null,
|
||||
breakMins: Int? = null,
|
||||
units: Float? = null,
|
||||
) {
|
||||
description?.let {
|
||||
(it.length < 3).validateField {
|
||||
@@ -243,11 +243,11 @@ class MainViewModel(
|
||||
type = type?.let { ShiftType.getEnumByType(it) },
|
||||
description = description,
|
||||
date = date,
|
||||
rateOfPay = rateOfPay?.toFloatOrNull(),
|
||||
rateOfPay = rateOfPay,
|
||||
timeIn = timeIn,
|
||||
timeOut = timeOut,
|
||||
breakMins = breakMins?.toIntOrNull(),
|
||||
units = units?.toFloatOrNull()
|
||||
breakMins = breakMins,
|
||||
units = units
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -430,7 +430,7 @@ class MainViewModel(
|
||||
return textString
|
||||
}
|
||||
|
||||
private fun refreshLiveData() {
|
||||
fun refreshLiveData() {
|
||||
_shiftLiveData.postValue(repository.readShiftsFromDatabase())
|
||||
}
|
||||
|
||||
@@ -471,7 +471,7 @@ class MainViewModel(
|
||||
return mFilterStore!!
|
||||
}
|
||||
|
||||
fun retrieveDurationText(mTimeIn: String?, mTimeOut: String?, mBreaks: Int): Float? {
|
||||
fun retrieveDurationText(mTimeIn: String?, mTimeOut: String?, mBreaks: Int?): Float? {
|
||||
try {
|
||||
return calculateDuration(mTimeIn,mTimeOut,mBreaks)
|
||||
}catch (e: IOException) {
|
||||
|
||||
Reference in New Issue
Block a user