diff --git a/app/src/main/java/com/appttude/h_mal/farmr/base/BaseActivity.kt b/app/src/main/java/com/appttude/h_mal/farmr/base/BaseActivity.kt index 16a8384..3960cf5 100644 --- a/app/src/main/java/com/appttude/h_mal/farmr/base/BaseActivity.kt +++ b/app/src/main/java/com/appttude/h_mal/farmr/base/BaseActivity.kt @@ -53,6 +53,6 @@ abstract class BaseActivity : AppCompatActivity(), KodeinAwar } fun setTitleInActionBar(title: String) { - setTitle(title) + supportActionBar?.title = title } } \ No newline at end of file diff --git a/app/src/main/java/com/appttude/h_mal/farmr/data/legacydb/LegacyDatabase.kt b/app/src/main/java/com/appttude/h_mal/farmr/data/legacydb/LegacyDatabase.kt index c413f9f..57e019e 100644 --- a/app/src/main/java/com/appttude/h_mal/farmr/data/legacydb/LegacyDatabase.kt +++ b/app/src/main/java/com/appttude/h_mal/farmr/data/legacydb/LegacyDatabase.kt @@ -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( _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() diff --git a/app/src/main/java/com/appttude/h_mal/farmr/di/ShiftApplication.kt b/app/src/main/java/com/appttude/h_mal/farmr/di/ShiftApplication.kt index ced4fb4..0e1532f 100644 --- a/app/src/main/java/com/appttude/h_mal/farmr/di/ShiftApplication.kt +++ b/app/src/main/java/com/appttude/h_mal/farmr/di/ShiftApplication.kt @@ -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()) } diff --git a/app/src/main/java/com/appttude/h_mal/farmr/ui/FragmentAddItem.kt b/app/src/main/java/com/appttude/h_mal/farmr/ui/FragmentAddItem.kt index f201bf1..1454eb8 100644 --- a/app/src/main/java/com/appttude/h_mal/farmr/ui/FragmentAddItem.kt +++ b/app/src/main/java/com/appttude/h_mal/farmr/ui/FragmentAddItem.kt @@ -51,11 +51,13 @@ class FragmentAddItem : BaseFragment(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(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(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(R.layout.fragment_add_item), hourlyDataView.show() durationHolder.show() } + R.id.piecerate -> { mType = ShiftType.PIECE wholeView.show() @@ -169,27 +174,62 @@ class FragmentAddItem : BaseFragment(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(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() diff --git a/app/src/main/java/com/appttude/h_mal/farmr/ui/FragmentMain.kt b/app/src/main/java/com/appttude/h_mal/farmr/ui/FragmentMain.kt index 6d053d6..b4f557b 100644 --- a/app/src/main/java/com/appttude/h_mal/farmr/ui/FragmentMain.kt +++ b/app/src/main/java/com/appttude/h_mal/farmr/ui/FragmentMain.kt @@ -27,7 +27,7 @@ import kotlin.system.exitProcess class FragmentMain : BaseFragment(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(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(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) + mAdapter.submitList(data as List) } } diff --git a/app/src/main/java/com/appttude/h_mal/farmr/ui/MainActivity.kt b/app/src/main/java/com/appttude/h_mal/farmr/ui/MainActivity.kt index 87bb453..187d4cd 100644 --- a/app/src/main/java/com/appttude/h_mal/farmr/ui/MainActivity.kt +++ b/app/src/main/java/com/appttude/h_mal/farmr/ui/MainActivity.kt @@ -22,10 +22,6 @@ import kotlin.system.exitProcess class MainActivity : BaseActivity() { private lateinit var toolbar: Toolbar - var selection: String? = null - var args: Array? = null - - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.main_view) @@ -57,11 +53,6 @@ class MainActivity : BaseActivity() { } } - - fun setActionBarTitle(title: String?) { - toolbar.title = title - } - // Storage Permissions private val REQUEST_EXTERNAL_STORAGE = 1 private val PERMISSIONS_STORAGE = arrayOf( diff --git a/app/src/main/java/com/appttude/h_mal/farmr/ui/ShiftRecyclerAdapter.kt b/app/src/main/java/com/appttude/h_mal/farmr/ui/ShiftListAdapter.kt similarity index 71% rename from app/src/main/java/com/appttude/h_mal/farmr/ui/ShiftRecyclerAdapter.kt rename to app/src/main/java/com/appttude/h_mal/farmr/ui/ShiftListAdapter.kt index acb99da..59d8987 100644 --- a/app/src/main/java/com/appttude/h_mal/farmr/ui/ShiftRecyclerAdapter.kt +++ b/app/src/main/java/com/appttude/h_mal/farmr/ui/ShiftListAdapter.kt @@ -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( - emptyViewId = R.layout.empty_list_view, - currentViewId = R.layout.list_item_1 -) { - override fun bindCurrentView(view: View, position: Int, data: ShiftObject) { +) : ListAdapter(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() { + override fun areItemsTheSame(oldItem: ShiftObject, newItem: ShiftObject): Boolean { + return oldItem.id == newItem.id + } + + override fun areContentsTheSame(oldItem: ShiftObject, newItem: ShiftObject): Boolean { + return oldItem == newItem + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/appttude/h_mal/farmr/utils/Formatting.kt b/app/src/main/java/com/appttude/h_mal/farmr/utils/Formatting.kt index 1877d8d..7be48db 100644 --- a/app/src/main/java/com/appttude/h_mal/farmr/utils/Formatting.kt +++ b/app/src/main/java/com/appttude/h_mal/farmr/utils/Formatting.kt @@ -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 { diff --git a/app/src/main/java/com/appttude/h_mal/farmr/utils/ViewUtils.kt b/app/src/main/java/com/appttude/h_mal/farmr/utils/ViewUtils.kt index 8432a0e..659b798 100644 --- a/app/src/main/java/com/appttude/h_mal/farmr/utils/ViewUtils.kt +++ b/app/src/main/java/com/appttude/h_mal/farmr/utils/ViewUtils.kt @@ -173,5 +173,7 @@ fun EditText.setDatePicker(onSelected: (String) -> Unit) { }, mYear, mMonth, mDay ) mDatePicker.setTitle("Select date") - mDatePicker.show() + setOnClickListener { + mDatePicker.show() + } } \ No newline at end of file diff --git a/app/src/main/java/com/appttude/h_mal/farmr/viewmodel/MainViewModel.kt b/app/src/main/java/com/appttude/h_mal/farmr/viewmodel/MainViewModel.kt index 6d7281e..08d1185 100644 --- a/app/src/main/java/com/appttude/h_mal/farmr/viewmodel/MainViewModel.kt +++ b/app/src/main/java/com/appttude/h_mal/farmr/viewmodel/MainViewModel.kt @@ -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) {