mirror of
https://github.com/hmalik144/Farmr.git
synced 2026-03-18 07:25:55 +00:00
Merge branch 'modern_architecture' into testsuite_expansion
# Conflicts: # app/build.gradle
This commit is contained in:
2
.idea/kotlinc.xml
generated
2
.idea/kotlinc.xml
generated
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="KotlinJpsPluginSettings">
|
<component name="KotlinJpsPluginSettings">
|
||||||
<option name="version" value="1.9.0" />
|
<option name="version" value="1.7.10" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -70,6 +70,6 @@ dependencies {
|
|||||||
def kodein_version = "6.2.1"
|
def kodein_version = "6.2.1"
|
||||||
implementation "org.kodein.di:kodein-di-generic-jvm:$kodein_version"
|
implementation "org.kodein.di:kodein-di-generic-jvm:$kodein_version"
|
||||||
implementation "org.kodein.di:kodein-di-framework-android-x:$kodein_version"
|
implementation "org.kodein.di:kodein-di-framework-android-x:$kodein_version"
|
||||||
/ * SQLite to excel */
|
/ * jxl * /
|
||||||
implementation 'com.ajts.androidmads.SQLite2Excel:library:1.0.2'
|
implementation 'net.sourceforge.jexcelapi:jxl:2.6.12'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,16 @@
|
|||||||
android:name="com.appttude.h_mal.farmr.data.legacydb.ShiftProvider"
|
android:name="com.appttude.h_mal.farmr.data.legacydb.ShiftProvider"
|
||||||
android:authorities="com.appttude.h_mal.farmr"
|
android:authorities="com.appttude.h_mal.farmr"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|
||||||
|
<provider
|
||||||
|
android:name="androidx.core.content.FileProvider"
|
||||||
|
android:authorities="com.appttude.h_mal.farmr.provider"
|
||||||
|
android:exported="false"
|
||||||
|
android:grantUriPermissions="true">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
|
android:resource="@xml/provider_path" />
|
||||||
|
</provider>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -7,6 +7,7 @@ import androidx.fragment.app.Fragment
|
|||||||
import androidx.fragment.app.createViewModelLazy
|
import androidx.fragment.app.createViewModelLazy
|
||||||
import com.appttude.h_mal.farmr.model.ViewState
|
import com.appttude.h_mal.farmr.model.ViewState
|
||||||
import com.appttude.h_mal.farmr.utils.getGenericClassAt
|
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 com.appttude.h_mal.farmr.viewmodel.ApplicationViewModelFactory
|
||||||
import org.kodein.di.KodeinAware
|
import org.kodein.di.KodeinAware
|
||||||
import org.kodein.di.android.x.kodein
|
import org.kodein.di.android.x.kodein
|
||||||
@@ -76,4 +77,6 @@ abstract class BaseFragment<V : BaseViewModel>(@LayoutRes contentLayoutId: Int)
|
|||||||
fun setTitle(title: String) {
|
fun setTitle(title: String) {
|
||||||
(requireActivity() as BaseActivity<*>).setTitleInActionBar(title)
|
(requireActivity() as BaseActivity<*>).setTitleInActionBar(title)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun popBackStack() = mActivity?.popBackStack()
|
||||||
}
|
}
|
||||||
@@ -13,11 +13,6 @@ open class BaseRecyclerAdapter<T: Any>(
|
|||||||
): RecyclerView.Adapter<ViewHolder>() {
|
): RecyclerView.Adapter<ViewHolder>() {
|
||||||
var list: List<T>? = null
|
var list: List<T>? = null
|
||||||
|
|
||||||
fun updateData(newList: List<T>) {
|
|
||||||
list = newList
|
|
||||||
notifyDataSetChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
return if (list.isNullOrEmpty()) {
|
return if (list.isNullOrEmpty()) {
|
||||||
val emptyViewHolder = parent.generateView(emptyViewId)
|
val emptyViewHolder = parent.generateView(emptyViewId)
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ data class Shift(
|
|||||||
timeOut,
|
timeOut,
|
||||||
duration,
|
duration,
|
||||||
breakTime,
|
breakTime,
|
||||||
duration,
|
0f,
|
||||||
rateOfPay,
|
rateOfPay,
|
||||||
(duration * rateOfPay).formatToTwoDp()
|
(duration * rateOfPay).formatToTwoDp()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,10 +4,6 @@ enum class ShiftType(val type: String){
|
|||||||
HOURLY("Hourly"),
|
HOURLY("Hourly"),
|
||||||
PIECE("Piece Rate");
|
PIECE("Piece Rate");
|
||||||
|
|
||||||
fun getEnumByType(type: String): ShiftType {
|
|
||||||
return values().first { it.type == type }
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getEnumByType(type: String): ShiftType {
|
fun getEnumByType(type: String): ShiftType {
|
||||||
return values().first { it.type == type }
|
return values().first { it.type == type }
|
||||||
|
|||||||
@@ -7,5 +7,9 @@ enum class Sortable(val label: String) {
|
|||||||
DESCRIPTION("Description"),
|
DESCRIPTION("Description"),
|
||||||
DURATION("Added"), UNITS("Duration"),
|
DURATION("Added"), UNITS("Duration"),
|
||||||
RATEOFPAY("Rate of pay"),
|
RATEOFPAY("Rate of pay"),
|
||||||
TOTALPAY("Total Pay")
|
TOTALPAY("Total Pay");
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val entries = Sortable.values()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.appttude.h_mal.farmr.model
|
||||||
|
|
||||||
|
data class Success(
|
||||||
|
val successMessage: String
|
||||||
|
)
|
||||||
@@ -12,6 +12,7 @@ import androidx.core.widget.doAfterTextChanged
|
|||||||
import com.appttude.h_mal.farmr.R
|
import com.appttude.h_mal.farmr.R
|
||||||
import com.appttude.h_mal.farmr.base.BaseFragment
|
import com.appttude.h_mal.farmr.base.BaseFragment
|
||||||
import com.appttude.h_mal.farmr.model.ShiftType
|
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.utils.setDatePicker
|
||||||
import com.appttude.h_mal.farmr.viewmodel.MainViewModel
|
import com.appttude.h_mal.farmr.viewmodel.MainViewModel
|
||||||
|
|
||||||
@@ -32,7 +33,6 @@ class FilterDataFragment : BaseFragment<MainViewModel>(R.layout.fragment_filter_
|
|||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
setTitle(getString(R.string.title_activity_filter_data))
|
setTitle(getString(R.string.title_activity_filter_data))
|
||||||
|
|
||||||
LocationET = view.findViewById(R.id.filterLocationEditText)
|
LocationET = view.findViewById(R.id.filterLocationEditText)
|
||||||
@@ -74,8 +74,8 @@ class FilterDataFragment : BaseFragment<MainViewModel>(R.layout.fragment_filter_
|
|||||||
id: Long
|
id: Long
|
||||||
) {
|
) {
|
||||||
type = when (position) {
|
type = when (position) {
|
||||||
1 -> ShiftType.HOURLY.toString()
|
1 -> ShiftType.HOURLY.type
|
||||||
2 -> ShiftType.PIECE.toString()
|
2 -> ShiftType.PIECE.type
|
||||||
else -> return
|
else -> return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,4 +89,9 @@ class FilterDataFragment : BaseFragment<MainViewModel>(R.layout.fragment_filter_
|
|||||||
override fun onClick(p0: View?) {
|
override fun onClick(p0: View?) {
|
||||||
submitFiltrationDetails()
|
submitFiltrationDetails()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onSuccess(data: Any?) {
|
||||||
|
super.onSuccess(data)
|
||||||
|
if (data is Success) popBackStack()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -14,8 +14,10 @@ import com.appttude.h_mal.farmr.R
|
|||||||
import com.appttude.h_mal.farmr.base.BackPressedListener
|
import com.appttude.h_mal.farmr.base.BackPressedListener
|
||||||
import com.appttude.h_mal.farmr.base.BaseFragment
|
import com.appttude.h_mal.farmr.base.BaseFragment
|
||||||
import com.appttude.h_mal.farmr.model.ShiftType
|
import com.appttude.h_mal.farmr.model.ShiftType
|
||||||
|
import com.appttude.h_mal.farmr.model.Success
|
||||||
import com.appttude.h_mal.farmr.utils.ID
|
import com.appttude.h_mal.farmr.utils.ID
|
||||||
import com.appttude.h_mal.farmr.utils.createDialog
|
import com.appttude.h_mal.farmr.utils.createDialog
|
||||||
|
import com.appttude.h_mal.farmr.utils.displayToast
|
||||||
import com.appttude.h_mal.farmr.utils.formatToTwoDpString
|
import com.appttude.h_mal.farmr.utils.formatToTwoDpString
|
||||||
import com.appttude.h_mal.farmr.utils.hide
|
import com.appttude.h_mal.farmr.utils.hide
|
||||||
import com.appttude.h_mal.farmr.utils.popBackStack
|
import com.appttude.h_mal.farmr.utils.popBackStack
|
||||||
@@ -123,6 +125,13 @@ class FragmentAddItem : BaseFragment<MainViewModel>(R.layout.fragment_add_item),
|
|||||||
viewModel.getCurrentShift(arguments!!.getLong(ID))?.run {
|
viewModel.getCurrentShift(arguments!!.getLong(ID))?.run {
|
||||||
mLocationEditText.setText(description)
|
mLocationEditText.setText(description)
|
||||||
mDateEditText.setText(date)
|
mDateEditText.setText(date)
|
||||||
|
|
||||||
|
// Set types
|
||||||
|
mType = ShiftType.getEnumByType(type)
|
||||||
|
mDescription = description
|
||||||
|
mDate = date
|
||||||
|
mPayRate = rateOfPay
|
||||||
|
|
||||||
when (ShiftType.getEnumByType(type)) {
|
when (ShiftType.getEnumByType(type)) {
|
||||||
ShiftType.HOURLY -> {
|
ShiftType.HOURLY -> {
|
||||||
mHourlyRadioButton.isChecked = true
|
mHourlyRadioButton.isChecked = true
|
||||||
@@ -132,16 +141,26 @@ class FragmentAddItem : BaseFragment<MainViewModel>(R.layout.fragment_add_item),
|
|||||||
mBreakEditText.setText(breakMins.toString())
|
mBreakEditText.setText(breakMins.toString())
|
||||||
val durationText = "${duration.formatToTwoDpString()} Hours"
|
val durationText = "${duration.formatToTwoDpString()} Hours"
|
||||||
mDurationTextView.text = durationText
|
mDurationTextView.text = durationText
|
||||||
|
|
||||||
|
// Set fields
|
||||||
|
mTimeIn = timeIn
|
||||||
|
mTimeOut = timeOut
|
||||||
|
mBreaks = breakMins
|
||||||
}
|
}
|
||||||
|
|
||||||
ShiftType.PIECE -> {
|
ShiftType.PIECE -> {
|
||||||
mHourlyRadioButton.isChecked = false
|
mHourlyRadioButton.isChecked = false
|
||||||
mPieceRadioButton.isChecked = true
|
mPieceRadioButton.isChecked = true
|
||||||
mUnitEditText.setText(units.formatToTwoDpString())
|
mUnitEditText.setText(units.formatToTwoDpString())
|
||||||
|
|
||||||
|
// Set piece rate units
|
||||||
|
mUnits = units
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mPayRateEditText.setText(rateOfPay.formatToTwoDpString())
|
mPayRateEditText.setText(rateOfPay.formatToTwoDpString())
|
||||||
mTotalPayTextView.text = totalPay.formatToTwoDpString()
|
mTotalPayTextView.text = totalPay.formatToTwoDpString()
|
||||||
|
|
||||||
|
calculateTotalPay()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return title
|
// Return title
|
||||||
@@ -268,4 +287,11 @@ class FragmentAddItem : BaseFragment<MainViewModel>(R.layout.fragment_add_item),
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onSuccess(data: Any?) {
|
||||||
|
super.onSuccess(data)
|
||||||
|
if (data is Success) {
|
||||||
|
displayToast(data.successMessage)
|
||||||
|
popBackStack()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -6,31 +6,41 @@ import android.app.Activity
|
|||||||
import android.app.AlertDialog
|
import android.app.AlertDialog
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
|
import androidx.core.content.FileProvider
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver
|
||||||
import com.appttude.h_mal.farmr.R
|
import com.appttude.h_mal.farmr.R
|
||||||
import com.appttude.h_mal.farmr.base.BackPressedListener
|
import com.appttude.h_mal.farmr.base.BackPressedListener
|
||||||
import com.appttude.h_mal.farmr.base.BaseFragment
|
import com.appttude.h_mal.farmr.base.BaseFragment
|
||||||
import com.appttude.h_mal.farmr.data.legacydb.ShiftObject
|
import com.appttude.h_mal.farmr.data.legacydb.ShiftObject
|
||||||
import com.appttude.h_mal.farmr.model.Order
|
import com.appttude.h_mal.farmr.model.Order
|
||||||
import com.appttude.h_mal.farmr.model.Sortable
|
import com.appttude.h_mal.farmr.model.Sortable
|
||||||
|
import com.appttude.h_mal.farmr.model.Success
|
||||||
import com.appttude.h_mal.farmr.utils.createDialog
|
import com.appttude.h_mal.farmr.utils.createDialog
|
||||||
|
import com.appttude.h_mal.farmr.utils.displayToast
|
||||||
|
import com.appttude.h_mal.farmr.utils.hide
|
||||||
import com.appttude.h_mal.farmr.utils.navigateToFragment
|
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.MainViewModel
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
import java.io.File
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
|
||||||
class FragmentMain : BaseFragment<MainViewModel>(R.layout.fragment_main), BackPressedListener {
|
class FragmentMain : BaseFragment<MainViewModel>(R.layout.fragment_main), BackPressedListener {
|
||||||
lateinit var activity: MainActivity
|
|
||||||
private lateinit var productListView: RecyclerView
|
private lateinit var productListView: RecyclerView
|
||||||
|
private lateinit var emptyView: View
|
||||||
private lateinit var mAdapter: ShiftListAdapter
|
private lateinit var mAdapter: ShiftListAdapter
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
setTitle("Shift List")
|
||||||
// Inflate the layout for this fragment
|
// Inflate the layout for this fragment
|
||||||
setHasOptionsMenu(true)
|
setHasOptionsMenu(true)
|
||||||
}
|
}
|
||||||
@@ -43,6 +53,15 @@ class FragmentMain : BaseFragment<MainViewModel>(R.layout.fragment_main), BackPr
|
|||||||
}
|
}
|
||||||
productListView = view.findViewById(R.id.list_item_view)
|
productListView = view.findViewById(R.id.list_item_view)
|
||||||
productListView.adapter = mAdapter
|
productListView.adapter = mAdapter
|
||||||
|
emptyView = view.findViewById(R.id.empty_view)
|
||||||
|
|
||||||
|
mAdapter.registerAdapterDataObserver(object : AdapterDataObserver() {
|
||||||
|
override fun onChanged() {
|
||||||
|
super.onChanged()
|
||||||
|
if (mAdapter.itemCount == 0) emptyView.show()
|
||||||
|
else emptyView.hide()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
view.findViewById<FloatingActionButton>(R.id.fab1).setOnClickListener {
|
view.findViewById<FloatingActionButton>(R.id.fab1).setOnClickListener {
|
||||||
navigateToFragment(FragmentAddItem(), name = "additem")
|
navigateToFragment(FragmentAddItem(), name = "additem")
|
||||||
@@ -58,8 +77,12 @@ class FragmentMain : BaseFragment<MainViewModel>(R.layout.fragment_main), BackPr
|
|||||||
override fun onSuccess(data: Any?) {
|
override fun onSuccess(data: Any?) {
|
||||||
super.onSuccess(data)
|
super.onSuccess(data)
|
||||||
if (data is List<*>) {
|
if (data is List<*>) {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
mAdapter.submitList(data as List<ShiftObject>)
|
mAdapter.submitList(data as List<ShiftObject>)
|
||||||
}
|
}
|
||||||
|
if (data is Success) {
|
||||||
|
displayToast(data.successMessage)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
@@ -79,12 +102,7 @@ class FragmentMain : BaseFragment<MainViewModel>(R.layout.fragment_main), BackPr
|
|||||||
}
|
}
|
||||||
|
|
||||||
R.id.filter_data -> {
|
R.id.filter_data -> {
|
||||||
// val fragmentTransaction: FragmentTransaction =
|
navigateToFragment(FilterDataFragment(), name = "filterdata")
|
||||||
// activity.fragmentManager!!.beginTransaction()
|
|
||||||
// fragmentTransaction.replace(R.id.container, FilterDataFragment())
|
|
||||||
// .addToBackStack("filterdata").commit()
|
|
||||||
// Todo: filter shift
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,8 +110,9 @@ class FragmentMain : BaseFragment<MainViewModel>(R.layout.fragment_main), BackPr
|
|||||||
sortData()
|
sortData()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.clear_filter -> {
|
R.id.clear_filter -> {
|
||||||
// Todo: Apply filter to list
|
viewModel.setFiltrationDetails(null, null, null, null)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +122,7 @@ class FragmentMain : BaseFragment<MainViewModel>(R.layout.fragment_main), BackPr
|
|||||||
.setTitle("Export?")
|
.setTitle("Export?")
|
||||||
.setMessage("Exporting current filtered data. Continue?")
|
.setMessage("Exporting current filtered data. Continue?")
|
||||||
.setNegativeButton(android.R.string.no, null)
|
.setNegativeButton(android.R.string.no, null)
|
||||||
.setPositiveButton(android.R.string.yes) { arg0, arg1 -> ExportData() }
|
.setPositiveButton(android.R.string.yes) { arg0, arg1 -> exportData() }
|
||||||
.create().show()
|
.create().show()
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(context, "Storage permissions required", Toast.LENGTH_SHORT)
|
Toast.makeText(context, "Storage permissions required", Toast.LENGTH_SHORT)
|
||||||
@@ -159,157 +178,29 @@ class FragmentMain : BaseFragment<MainViewModel>(R.layout.fragment_main), BackPr
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ExportData() {
|
private fun exportData() {
|
||||||
// val permission =
|
val permission =
|
||||||
// ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
ActivityCompat.checkSelfPermission(requireActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||||
// if (permission != PackageManager.PERMISSION_GRANTED) {
|
if (permission != PackageManager.PERMISSION_GRANTED) {
|
||||||
// Toast.makeText(context, "Storage permissions not granted", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, "Storage permissions not granted", Toast.LENGTH_SHORT).show()
|
||||||
// return
|
return
|
||||||
// }
|
|
||||||
// shiftsDbhelper = ShiftsDbHelper(context)
|
|
||||||
// val database = shiftsDbhelper!!.writableDatabase
|
|
||||||
// val projection_export = arrayOf<String?>(
|
|
||||||
// ShiftsEntry.COLUMN_SHIFT_DESCRIPTION,
|
|
||||||
// ShiftsEntry.COLUMN_SHIFT_DATE,
|
|
||||||
// ShiftsEntry.COLUMN_SHIFT_TIME_IN,
|
|
||||||
// ShiftsEntry.COLUMN_SHIFT_TIME_OUT,
|
|
||||||
// ShiftsEntry.COLUMN_SHIFT_BREAK,
|
|
||||||
// ShiftsEntry.COLUMN_SHIFT_DURATION,
|
|
||||||
// ShiftsEntry.COLUMN_SHIFT_TYPE,
|
|
||||||
// ShiftsEntry.COLUMN_SHIFT_UNIT,
|
|
||||||
// ShiftsEntry.COLUMN_SHIFT_PAYRATE,
|
|
||||||
// ShiftsEntry.COLUMN_SHIFT_TOTALPAY
|
|
||||||
// )
|
|
||||||
// val cursor = activity.contentResolver.query(
|
|
||||||
// ShiftsEntry.CONTENT_URI,
|
|
||||||
// projection_export,
|
|
||||||
// activity.selection,
|
|
||||||
// activity.args,
|
|
||||||
// activity.sortOrder
|
|
||||||
// )
|
|
||||||
// database.delete(ShiftsEntry.TABLE_NAME_EXPORT, null, null)
|
|
||||||
// var totalDuration = 0.00f
|
|
||||||
// var totalUnits = 0.00f
|
|
||||||
// var totalPay = 0.00f
|
|
||||||
// try {
|
|
||||||
// while (cursor!!.moveToNext()) {
|
|
||||||
// val descriptionColumnIndex =
|
|
||||||
// cursor.getString(cursor.getColumnIndexOrThrow(ShiftsEntry.COLUMN_SHIFT_DESCRIPTION))
|
|
||||||
// val dateColumnIndex =
|
|
||||||
// cursor.getString(cursor.getColumnIndexOrThrow(ShiftsEntry.COLUMN_SHIFT_DATE))
|
|
||||||
// val timeInColumnIndex =
|
|
||||||
// cursor.getString(cursor.getColumnIndexOrThrow(ShiftsEntry.COLUMN_SHIFT_TIME_IN))
|
|
||||||
// val timeOutColumnIndex =
|
|
||||||
// cursor.getString(cursor.getColumnIndexOrThrow(ShiftsEntry.COLUMN_SHIFT_TIME_OUT))
|
|
||||||
// val durationColumnIndex =
|
|
||||||
// cursor.getFloat(cursor.getColumnIndexOrThrow(ShiftsEntry.COLUMN_SHIFT_DURATION))
|
|
||||||
// val breakOutColumnIndex =
|
|
||||||
// cursor.getInt(cursor.getColumnIndexOrThrow(ShiftsEntry.COLUMN_SHIFT_BREAK))
|
|
||||||
// val typeColumnIndex =
|
|
||||||
// cursor.getString(cursor.getColumnIndexOrThrow(ShiftsEntry.COLUMN_SHIFT_TYPE))
|
|
||||||
// val unitColumnIndex =
|
|
||||||
// cursor.getFloat(cursor.getColumnIndexOrThrow(ShiftsEntry.COLUMN_SHIFT_UNIT))
|
|
||||||
// val payrateColumnIndex =
|
|
||||||
// cursor.getFloat(cursor.getColumnIndexOrThrow(ShiftsEntry.COLUMN_SHIFT_PAYRATE))
|
|
||||||
// val totalpayColumnIndex =
|
|
||||||
// cursor.getFloat(cursor.getColumnIndexOrThrow(ShiftsEntry.COLUMN_SHIFT_TOTALPAY))
|
|
||||||
// totalUnits = totalUnits + unitColumnIndex
|
|
||||||
// totalDuration = totalDuration + durationColumnIndex
|
|
||||||
// totalPay = totalPay + totalpayColumnIndex
|
|
||||||
// val values = ContentValues()
|
|
||||||
// values.put(ShiftsEntry.COLUMN_SHIFT_DESCRIPTION, descriptionColumnIndex)
|
|
||||||
// values.put(ShiftsEntry.COLUMN_SHIFT_DATE, dateColumnIndex)
|
|
||||||
// values.put(ShiftsEntry.COLUMN_SHIFT_TIME_IN, timeInColumnIndex)
|
|
||||||
// values.put(ShiftsEntry.COLUMN_SHIFT_TIME_OUT, timeOutColumnIndex)
|
|
||||||
// values.put(ShiftsEntry.COLUMN_SHIFT_BREAK, breakOutColumnIndex)
|
|
||||||
// values.put(ShiftsEntry.COLUMN_SHIFT_DURATION, durationColumnIndex)
|
|
||||||
// values.put(ShiftsEntry.COLUMN_SHIFT_TYPE, typeColumnIndex)
|
|
||||||
// values.put(ShiftsEntry.COLUMN_SHIFT_UNIT, unitColumnIndex)
|
|
||||||
// values.put(ShiftsEntry.COLUMN_SHIFT_PAYRATE, payrateColumnIndex)
|
|
||||||
// values.put(ShiftsEntry.COLUMN_SHIFT_TOTALPAY, totalpayColumnIndex)
|
|
||||||
// database.insert(ShiftsEntry.TABLE_NAME_EXPORT, null, values)
|
|
||||||
// }
|
|
||||||
// } catch (e: Exception) {
|
|
||||||
// Log.e("FragmentMain", "ExportData: ", e)
|
|
||||||
// } finally {
|
|
||||||
// val values = ContentValues()
|
|
||||||
// values.put(ShiftsEntry.COLUMN_SHIFT_DESCRIPTION, "")
|
|
||||||
// values.put(ShiftsEntry.COLUMN_SHIFT_DATE, "")
|
|
||||||
// values.put(ShiftsEntry.COLUMN_SHIFT_TIME_IN, "")
|
|
||||||
// values.put(ShiftsEntry.COLUMN_SHIFT_TIME_OUT, "")
|
|
||||||
// values.put(ShiftsEntry.COLUMN_SHIFT_BREAK, "Total duration:")
|
|
||||||
// values.put(ShiftsEntry.COLUMN_SHIFT_DURATION, totalDuration)
|
|
||||||
// values.put(ShiftsEntry.COLUMN_SHIFT_TYPE, "Total units:")
|
|
||||||
// values.put(ShiftsEntry.COLUMN_SHIFT_UNIT, totalUnits)
|
|
||||||
// values.put(ShiftsEntry.COLUMN_SHIFT_PAYRATE, "Total pay:")
|
|
||||||
// values.put(ShiftsEntry.COLUMN_SHIFT_TOTALPAY, totalPay)
|
|
||||||
// database.insert(ShiftsEntry.TABLE_NAME_EXPORT, null, values)
|
|
||||||
// cursor!!.close()
|
|
||||||
// }
|
|
||||||
// val savePath = Environment.getExternalStorageDirectory().toString() + "/ShifttrackerTemp"
|
|
||||||
// val file = File(savePath)
|
|
||||||
// if (!file.exists()) {
|
|
||||||
// file.mkdirs()
|
|
||||||
// }
|
|
||||||
// val sqLiteToExcel = SQLiteToExcel(context, "shifts.db", savePath)
|
|
||||||
// sqLiteToExcel.exportSingleTable(
|
|
||||||
// "shiftsexport",
|
|
||||||
// "shifthistory.xls",
|
|
||||||
// object : ExportListener {
|
|
||||||
// override fun onStart() {}
|
|
||||||
// override fun onCompleted(filePath: String) {
|
|
||||||
// Toast.makeText(context, filePath, Toast.LENGTH_SHORT).show()
|
|
||||||
// val newPath = Uri.parse("file://$savePath/shifthistory.xls")
|
|
||||||
// val builder = VmPolicy.Builder()
|
|
||||||
// StrictMode.setVmPolicy(builder.build())
|
|
||||||
// val emailintent = Intent(Intent.ACTION_SEND)
|
|
||||||
// emailintent.type = "application/vnd.ms-excel"
|
|
||||||
// emailintent.putExtra(Intent.EXTRA_SUBJECT, "historic shifts")
|
|
||||||
// emailintent.putExtra(Intent.EXTRA_TEXT, "I'm email body.")
|
|
||||||
// emailintent.putExtra(Intent.EXTRA_STREAM, newPath)
|
|
||||||
// startActivity(Intent.createChooser(emailintent, "Send Email"))
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun onError(e: Exception) {
|
|
||||||
// println("Error msg: $e")
|
|
||||||
// Toast.makeText(context, "Failed to Export data", Toast.LENGTH_SHORT).show()
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("DefaultLocale")
|
val fileName = "shifthistory.xls"
|
||||||
fun buildInfoString(
|
val file = File(requireContext().externalCacheDir, fileName)
|
||||||
totalDuration: Float,
|
|
||||||
countOfTypeH: Int,
|
viewModel.createExcelSheet(file)?.let {
|
||||||
countOfTypeP: Int,
|
val intent = Intent(Intent.ACTION_VIEW)
|
||||||
totalUnits: Float,
|
val excelUri = FileProvider.getUriForFile(
|
||||||
totalPay: Float,
|
requireContext(),
|
||||||
lines: Int
|
requireContext().applicationContext.packageName + ".provider",
|
||||||
): String {
|
file
|
||||||
var textString: String
|
)
|
||||||
textString = "$lines Shifts"
|
intent.setDataAndType(excelUri, "application/vnd.ms-excel")
|
||||||
if (countOfTypeH != 0 && countOfTypeP != 0) {
|
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
textString = "$textString ($countOfTypeH Hourly/$countOfTypeP Piece Rate)"
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
if (countOfTypeH != 0) {
|
|
||||||
textString = """
|
|
||||||
$textString
|
|
||||||
Total Hours: ${String.format("%.2f", totalDuration)}
|
|
||||||
""".trimIndent()
|
|
||||||
}
|
|
||||||
if (countOfTypeP != 0) {
|
|
||||||
textString = """
|
|
||||||
$textString
|
|
||||||
Total Units: ${String.format("%.2f", totalUnits)}
|
|
||||||
""".trimIndent()
|
|
||||||
}
|
|
||||||
if (totalPay != 0f) {
|
|
||||||
textString = """
|
|
||||||
$textString
|
|
||||||
Total Pay: ${"$"}${String.format("%.2f", totalPay)}
|
|
||||||
""".trimIndent()
|
|
||||||
}
|
|
||||||
return textString
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRequestPermissionsResult(
|
override fun onRequestPermissionsResult(
|
||||||
@@ -335,7 +226,7 @@ class FragmentMain : BaseFragment<MainViewModel>(R.layout.fragment_main), BackPr
|
|||||||
.setTitle("Export?")
|
.setTitle("Export?")
|
||||||
.setMessage("Exporting current filtered data. Continue?")
|
.setMessage("Exporting current filtered data. Continue?")
|
||||||
.setNegativeButton(android.R.string.no, null)
|
.setNegativeButton(android.R.string.no, null)
|
||||||
.setPositiveButton(android.R.string.yes) { arg0, arg1 -> ExportData() }.create().show()
|
.setPositiveButton(android.R.string.yes) { arg0, arg1 -> exportData() }.create().show()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkStoragePermissions(activity: Activity?): Boolean {
|
fun checkStoragePermissions(activity: Activity?): Boolean {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.appttude.h_mal.farmr.utils
|
|||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
fun String.formatToTwoDp(): Float {
|
fun String.formatToTwoDp(): Float {
|
||||||
@@ -32,6 +33,11 @@ fun Calendar.getTimeString(): String {
|
|||||||
return format.format(time)
|
return format.format(time)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun String.convertDateString(format: String = DATE_FORMAT): Date? {
|
||||||
|
val formatter = SimpleDateFormat(format, Locale.getDefault())
|
||||||
|
return formatter.parse(this)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* turns "HH:mm" into an hour and minutes pair
|
* turns "HH:mm" into an hour and minutes pair
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,11 +1,26 @@
|
|||||||
package com.appttude.h_mal.farmr.viewmodel
|
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.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import com.appttude.h_mal.farmr.base.BaseViewModel
|
import com.appttude.h_mal.farmr.base.BaseViewModel
|
||||||
import com.appttude.h_mal.farmr.data.Repository
|
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.ShiftObject
|
||||||
|
import com.appttude.h_mal.farmr.data.legacydb.ShiftsContract.ShiftsEntry.COLUMN_SHIFT_BREAK
|
||||||
|
import com.appttude.h_mal.farmr.data.legacydb.ShiftsContract.ShiftsEntry.COLUMN_SHIFT_DATE
|
||||||
|
import com.appttude.h_mal.farmr.data.legacydb.ShiftsContract.ShiftsEntry.COLUMN_SHIFT_DESCRIPTION
|
||||||
|
import com.appttude.h_mal.farmr.data.legacydb.ShiftsContract.ShiftsEntry.COLUMN_SHIFT_DURATION
|
||||||
|
import com.appttude.h_mal.farmr.data.legacydb.ShiftsContract.ShiftsEntry.COLUMN_SHIFT_PAYRATE
|
||||||
|
import com.appttude.h_mal.farmr.data.legacydb.ShiftsContract.ShiftsEntry.COLUMN_SHIFT_TIME_IN
|
||||||
|
import com.appttude.h_mal.farmr.data.legacydb.ShiftsContract.ShiftsEntry.COLUMN_SHIFT_TIME_OUT
|
||||||
|
import com.appttude.h_mal.farmr.data.legacydb.ShiftsContract.ShiftsEntry.COLUMN_SHIFT_TOTALPAY
|
||||||
|
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.DESCRIPTION
|
||||||
import com.appttude.h_mal.farmr.data.prefs.TIME_IN
|
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.TIME_OUT
|
||||||
@@ -15,14 +30,24 @@ import com.appttude.h_mal.farmr.model.Order
|
|||||||
import com.appttude.h_mal.farmr.model.Shift
|
import com.appttude.h_mal.farmr.model.Shift
|
||||||
import com.appttude.h_mal.farmr.model.ShiftType
|
import com.appttude.h_mal.farmr.model.ShiftType
|
||||||
import com.appttude.h_mal.farmr.model.Sortable
|
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.calculateDuration
|
||||||
|
import com.appttude.h_mal.farmr.utils.convertDateString
|
||||||
import com.appttude.h_mal.farmr.utils.dateStringIsValid
|
import com.appttude.h_mal.farmr.utils.dateStringIsValid
|
||||||
import com.appttude.h_mal.farmr.utils.formatToTwoDp
|
import com.appttude.h_mal.farmr.utils.formatToTwoDp
|
||||||
import com.appttude.h_mal.farmr.utils.getTimeString
|
import com.appttude.h_mal.farmr.utils.getTimeString
|
||||||
import com.appttude.h_mal.farmr.utils.sortedByOrder
|
import com.appttude.h_mal.farmr.utils.sortedByOrder
|
||||||
import com.appttude.h_mal.farmr.utils.timeStringIsValid
|
import com.appttude.h_mal.farmr.utils.timeStringIsValid
|
||||||
|
import jxl.Workbook
|
||||||
|
import jxl.WorkbookSettings
|
||||||
|
import jxl.write.Label
|
||||||
|
import jxl.write.WritableWorkbook
|
||||||
|
import jxl.write.WriteException
|
||||||
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
|
||||||
class MainViewModel(
|
class MainViewModel(
|
||||||
@@ -38,7 +63,8 @@ class MainViewModel(
|
|||||||
private var mFilterStore: FilterStore? = null
|
private var mFilterStore: FilterStore? = null
|
||||||
|
|
||||||
private val observer = Observer<List<ShiftObject>> {
|
private val observer = Observer<List<ShiftObject>> {
|
||||||
onSuccess(it.sortList(mSort, mOrder))
|
val result = it.applyFilters().sortList(mSort, mOrder)
|
||||||
|
onSuccess(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -47,6 +73,47 @@ class MainViewModel(
|
|||||||
shiftLiveData.observeForever(observer)
|
shiftLiveData.observeForever(observer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun List<ShiftObject>.applyFilters(): List<ShiftObject> {
|
||||||
|
val filter = getFiltrationDetails()
|
||||||
|
|
||||||
|
return filter { s ->
|
||||||
|
comparedStrings(filter.type, s.type) &&
|
||||||
|
comparedStringsContains(filter.description, s.description) &&
|
||||||
|
(isBetween(filter.dateFrom, filter.dateTo, s.date) ?: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun comparedStrings(first: String?, second: String?): Boolean {
|
||||||
|
return when (compareValues(first, second)) {
|
||||||
|
-1, 0, 1 -> true
|
||||||
|
else -> {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun comparedStringsContains(first: String?, second: String?): Boolean {
|
||||||
|
first?.let {
|
||||||
|
(second?.contains(it))?.let { c -> return c }
|
||||||
|
}
|
||||||
|
|
||||||
|
return comparedStrings(first, second)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isBetween(fromDate: String?, toDate: String?, compareWith: String): Boolean? {
|
||||||
|
val first = fromDate?.convertDateString()
|
||||||
|
val second = toDate?.convertDateString()
|
||||||
|
|
||||||
|
if (first == null && second == null) return null
|
||||||
|
val compareDate = compareWith.convertDateString() ?: return null
|
||||||
|
|
||||||
|
if (second == null) return compareDate.after(first)
|
||||||
|
if (first == null) return compareDate.before(second)
|
||||||
|
|
||||||
|
return compareDate.after(first) && compareDate.before(second)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun onCleared() {
|
override fun onCleared() {
|
||||||
shiftLiveData.removeObserver(observer)
|
shiftLiveData.removeObserver(observer)
|
||||||
super.onCleared()
|
super.onCleared()
|
||||||
@@ -121,7 +188,7 @@ class MainViewModel(
|
|||||||
onError("Date format is invalid")
|
onError("Date format is invalid")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
(rateOfPay.toFloat() >= 0.00).validateField {
|
(rateOfPay >= 0.00).validateField {
|
||||||
onError("Rate of pay is invalid")
|
onError("Rate of pay is invalid")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -139,7 +206,7 @@ class MainViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
doTry {
|
doTry {
|
||||||
insertShiftIntoDatabase(
|
val result = insertShiftIntoDatabase(
|
||||||
ShiftType.HOURLY,
|
ShiftType.HOURLY,
|
||||||
description,
|
description,
|
||||||
date,
|
date,
|
||||||
@@ -149,6 +216,8 @@ class MainViewModel(
|
|||||||
breakMins,
|
breakMins,
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (result) onSuccess(Success("Shift successfully added"))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -178,7 +247,7 @@ class MainViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
doTry {
|
doTry {
|
||||||
insertShiftIntoDatabase(
|
val result = insertShiftIntoDatabase(
|
||||||
type = ShiftType.PIECE,
|
type = ShiftType.PIECE,
|
||||||
description = description,
|
description = description,
|
||||||
date = date,
|
date = date,
|
||||||
@@ -188,6 +257,7 @@ class MainViewModel(
|
|||||||
null,
|
null,
|
||||||
units = units
|
units = units
|
||||||
)
|
)
|
||||||
|
if (result) onSuccess(Success("New shift successfully added"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,7 +273,7 @@ class MainViewModel(
|
|||||||
units: Float? = null,
|
units: Float? = null,
|
||||||
) {
|
) {
|
||||||
description?.let {
|
description?.let {
|
||||||
(it.length < 3).validateField {
|
(it.length > 3).validateField {
|
||||||
onError("Description length should be longer")
|
onError("Description length should be longer")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -213,7 +283,7 @@ class MainViewModel(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
rateOfPay?.let {
|
rateOfPay?.let {
|
||||||
(it.toFloat() >= 0.00).validateField {
|
(it >= 0.00).validateField {
|
||||||
onError("Rate of pay is invalid")
|
onError("Rate of pay is invalid")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -232,13 +302,13 @@ class MainViewModel(
|
|||||||
onError("Time out format is in correct")
|
onError("Time out format is in correct")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
breakMins?.let { it.toInt() > 0 }?.validateField {
|
breakMins?.let { it >= 0 }?.validateField {
|
||||||
onError("Break in minutes is invalid")
|
onError("Break in minutes is invalid")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
doTry {
|
doTry {
|
||||||
updateShiftInDatabase(
|
val result = updateShiftInDatabase(
|
||||||
id,
|
id,
|
||||||
type = type?.let { ShiftType.getEnumByType(it) },
|
type = type?.let { ShiftType.getEnumByType(it) },
|
||||||
description = description,
|
description = description,
|
||||||
@@ -249,6 +319,8 @@ class MainViewModel(
|
|||||||
breakMins = breakMins,
|
breakMins = breakMins,
|
||||||
units = units
|
units = units
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (result) onSuccess(Success("Shift successfully updated"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,7 +350,7 @@ class MainViewModel(
|
|||||||
timeOut: String? = null,
|
timeOut: String? = null,
|
||||||
breakMins: Int? = null,
|
breakMins: Int? = null,
|
||||||
units: Float? = null,
|
units: Float? = null,
|
||||||
) {
|
): Boolean {
|
||||||
val currentShift = repository.readSingleShiftFromDatabase(id)?.copyToShift()
|
val currentShift = repository.readSingleShiftFromDatabase(id)?.copyToShift()
|
||||||
?: throw IOException("Cannot update shift as it does not exist")
|
?: throw IOException("Cannot update shift as it does not exist")
|
||||||
|
|
||||||
@@ -352,7 +424,7 @@ class MainViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repository.updateShiftIntoDatabase(id, shift)
|
return repository.updateShiftIntoDatabase(id, shift)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun insertShiftIntoDatabase(
|
private fun insertShiftIntoDatabase(
|
||||||
@@ -364,7 +436,7 @@ class MainViewModel(
|
|||||||
timeOut: String?,
|
timeOut: String?,
|
||||||
breakMins: Int?,
|
breakMins: Int?,
|
||||||
units: Float?,
|
units: Float?,
|
||||||
) {
|
): Boolean {
|
||||||
val shift = when (type) {
|
val shift = when (type) {
|
||||||
ShiftType.HOURLY -> {
|
ShiftType.HOURLY -> {
|
||||||
if (timeIn.isNullOrBlank() && timeOut.isNullOrBlank()) throw IOException("Time in and time out are null")
|
if (timeIn.isNullOrBlank() && timeOut.isNullOrBlank()) throw IOException("Time in and time out are null")
|
||||||
@@ -392,7 +464,7 @@ class MainViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repository.insertShiftIntoDatabase(shift)
|
return repository.insertShiftIntoDatabase(shift)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -404,30 +476,21 @@ class MainViewModel(
|
|||||||
totalPay: Float,
|
totalPay: Float,
|
||||||
lines: Int
|
lines: Int
|
||||||
): String {
|
): String {
|
||||||
var textString: String
|
val stringBuilder = StringBuilder("$lines Shifts").append("\n")
|
||||||
textString = "$lines Shifts"
|
|
||||||
if (countOfHourly != 0 && countOfPiece != 0) {
|
if (countOfHourly != 0 && countOfPiece != 0) {
|
||||||
textString = "$textString ($countOfHourly Hourly/$countOfPiece Piece Rate)"
|
stringBuilder.append(" ($countOfHourly Hourly/$countOfPiece Piece Rate)").append("\n")
|
||||||
}
|
}
|
||||||
if (countOfHourly != 0) {
|
if (countOfHourly != 0) {
|
||||||
textString = """
|
stringBuilder.append("Total Hours: ").append(totalDuration).append("\n")
|
||||||
$textString
|
|
||||||
Total Hours: ${String.format("%.2f", totalDuration)}
|
|
||||||
""".trimIndent()
|
|
||||||
}
|
}
|
||||||
if (countOfPiece != 0) {
|
if (countOfPiece != 0) {
|
||||||
textString = """
|
stringBuilder.append("Total Units: ").append(totalUnits).append("\n")
|
||||||
$textString
|
|
||||||
Total Units: ${String.format("%.2f", totalUnits)}
|
|
||||||
""".trimIndent()
|
|
||||||
}
|
}
|
||||||
if (totalPay != 0f) {
|
if (totalPay != 0f) {
|
||||||
textString = """
|
stringBuilder.append("Total Pay: ").append(CURRENCY).append(totalPay).append("\n")
|
||||||
$textString
|
|
||||||
Total Pay: ${"$"}${String.format("%.2f", totalPay)}
|
|
||||||
""".trimIndent()
|
|
||||||
}
|
}
|
||||||
return textString
|
return stringBuilder.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun refreshLiveData() {
|
fun refreshLiveData() {
|
||||||
@@ -458,6 +521,8 @@ class MainViewModel(
|
|||||||
type: String?
|
type: String?
|
||||||
) {
|
) {
|
||||||
repository.setFilteringDetailsInPrefs(description, dateFrom, dateTo, type)
|
repository.setFilteringDetailsInPrefs(description, dateFrom, dateTo, type)
|
||||||
|
onSuccess(Success("Filter(s) successfully applied"))
|
||||||
|
refreshLiveData()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getFiltrationDetails(): FilterStore {
|
fun getFiltrationDetails(): FilterStore {
|
||||||
@@ -480,4 +545,83 @@ class MainViewModel(
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresPermission(WRITE_EXTERNAL_STORAGE)
|
||||||
|
fun createExcelSheet(file: File): File? {
|
||||||
|
val wbSettings = WorkbookSettings().apply {
|
||||||
|
locale = Locale("en", "EN")
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
val workbook: WritableWorkbook = Workbook.createWorkbook(file, wbSettings)
|
||||||
|
val sheet = workbook.createSheet("Shifts", 0)
|
||||||
|
// Write column headers
|
||||||
|
val headers = listOf(
|
||||||
|
Label(0, 0, _ID),
|
||||||
|
Label(1, 0, COLUMN_SHIFT_TYPE),
|
||||||
|
Label(2, 0, COLUMN_SHIFT_DESCRIPTION),
|
||||||
|
Label(3, 0, COLUMN_SHIFT_DATE),
|
||||||
|
Label(4, 0, COLUMN_SHIFT_TIME_IN),
|
||||||
|
Label(5, 0, COLUMN_SHIFT_TIME_OUT),
|
||||||
|
Label(6, 0, "$COLUMN_SHIFT_BREAK (in mins)"),
|
||||||
|
Label(7, 0, COLUMN_SHIFT_DURATION),
|
||||||
|
Label(8, 0, COLUMN_SHIFT_UNIT),
|
||||||
|
Label(9, 0, COLUMN_SHIFT_PAYRATE),
|
||||||
|
Label(10, 0, COLUMN_SHIFT_TOTALPAY)
|
||||||
|
)
|
||||||
|
// table content
|
||||||
|
if (shiftLiveData.value.isNullOrEmpty()) {
|
||||||
|
onError("No data to parse into excel file")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val sortAndOrder = getSortAndOrder()
|
||||||
|
val data = shiftLiveData.value!!.applyFilters().sortList(sortAndOrder.first, sortAndOrder.second)
|
||||||
|
var currentRow = 0
|
||||||
|
val cells = data.mapIndexed { index, shift ->
|
||||||
|
currentRow += 1
|
||||||
|
listOf(
|
||||||
|
Label(0, currentRow, shift.id.toString()),
|
||||||
|
Label(1, currentRow, shift.type),
|
||||||
|
Label(2, currentRow, shift.description),
|
||||||
|
Label(3, currentRow, shift.date),
|
||||||
|
Label(4, currentRow, shift.timeIn),
|
||||||
|
Label(5, currentRow, shift.timeOut),
|
||||||
|
Label(6, currentRow, shift.breakMins.toString()),
|
||||||
|
Label(7, currentRow, shift.duration.toString()),
|
||||||
|
Label(8, currentRow, shift.units.toString()),
|
||||||
|
Label(9, currentRow, shift.rateOfPay.toString()),
|
||||||
|
Label(10, currentRow, shift.totalPay.toString())
|
||||||
|
)
|
||||||
|
}.flatten()
|
||||||
|
|
||||||
|
currentRow += 1
|
||||||
|
val footer = listOf(
|
||||||
|
Label(0, currentRow, "Total:"),
|
||||||
|
Label(7, currentRow, data.sumOf { it.duration.toDouble() }.toString()),
|
||||||
|
Label(8, currentRow, data.sumOf { it.units.toDouble() }.toString()),
|
||||||
|
Label(10, currentRow, data.sumOf { it.totalPay.toDouble() }.toString())
|
||||||
|
)
|
||||||
|
val content = listOf(headers, cells, footer).flatten()
|
||||||
|
|
||||||
|
// Write content to sheet
|
||||||
|
try {
|
||||||
|
content.forEach { c -> sheet.addCell(c) }
|
||||||
|
} catch (e: WriteException) {
|
||||||
|
onError("Failed to write excel sheet")
|
||||||
|
return null
|
||||||
|
} catch (e: WriteException) {
|
||||||
|
onError("Failed to write excel sheet")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
workbook.write()
|
||||||
|
workbook.close()
|
||||||
|
|
||||||
|
return file
|
||||||
|
} catch (e: IOException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
onError("Failed to generate excel sheet of shifts")
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 90 KiB |
@@ -1,9 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportHeight="24.0"
|
|
||||||
android:viewportWidth="24.0">
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zm1,15h-2v-6h2v6zm0,-8h-2V7h2v2z" />
|
|
||||||
</vector>
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<vector
|
|
||||||
android:height="108dp"
|
|
||||||
android:width="108dp"
|
|
||||||
android:viewportHeight="108"
|
|
||||||
android:viewportWidth="108"
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="#3DDC84"
|
|
||||||
android:pathData="M0,0h108v108h-108z"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<vector
|
|
||||||
android:height="108dp"
|
|
||||||
android:width="108dp"
|
|
||||||
android:viewportHeight="108"
|
|
||||||
android:viewportWidth="108"
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="#3DDC84"
|
|
||||||
android:pathData="M0,0h108v108h-108z"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
|
|
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportHeight="24.0"
|
|
||||||
android:viewportWidth="24.0">
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="M11.5,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.9,2 2,2zm6.5,-6v-5.5c0,-3.07 -2.13,-5.64 -5,-6.32V3.5c0,-0.83 -0.67,-1.5 -1.5,-1.5S10,2.67 10,3.5v0.68c-2.87,0.68 -5,3.25 -5,6.32V16l-2,2v1h17v-1l-2,-2z" />
|
|
||||||
</vector>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportHeight="24.0"
|
|
||||||
android:viewportWidth="24.0">
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01,-0.25 1.97,-0.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0,-4.42,-3.58,-8,-8,-8zm0 14c-3.31 0,-6,-2.69,-6,-6 0,-1.01 0.25,-1.97 0.7,-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4,-4,-4,-4v3z" />
|
|
||||||
</vector>
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 KiB |
@@ -1,13 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:id="@+id/recycler">
|
|
||||||
|
|
||||||
</androidx.recyclerview.widget.RecyclerView>
|
|
||||||
</FrameLayout>
|
|
||||||
@@ -23,4 +23,9 @@
|
|||||||
android:src="@drawable/add"
|
android:src="@drawable/add"
|
||||||
app:backgroundTint="@color/colorPrimary" />
|
app:backgroundTint="@color/colorPrimary" />
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:visibility="gone"
|
||||||
|
layout="@layout/empty_list_view"
|
||||||
|
android:id="@+id/empty_view"/>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Farmr</string>
|
<string name="app_name">Farmr</string>
|
||||||
<string name="action_settings">Settings</string>
|
|
||||||
<string name="category_ach">Shifts</string>
|
<string name="category_ach">Shifts</string>
|
||||||
|
|
||||||
<string name="add_item_title">Add Shift</string>
|
<string name="add_item_title">Add Shift</string>
|
||||||
<string name="edit_item_title">Edit Shift</string>
|
<string name="edit_item_title">Edit Shift</string>
|
||||||
<string name="delete_item">Delete Shift</string>
|
|
||||||
<string name="insert_item_failed">failed to insert Shift</string>
|
<string name="insert_item_failed">failed to insert Shift</string>
|
||||||
<string name="insert_item_successful">Shift successfully added</string>
|
<string name="insert_item_successful">Shift successfully added</string>
|
||||||
<string name="update_item_failed">Update Failed</string>
|
<string name="update_item_failed">Update Failed</string>
|
||||||
@@ -25,11 +23,6 @@
|
|||||||
<!-- Example General settings -->
|
<!-- Example General settings -->
|
||||||
<string name="pref_header_general">General</string>
|
<string name="pref_header_general">General</string>
|
||||||
|
|
||||||
<string name="pref_title_social_recommendations">Enable social recommendations</string>
|
|
||||||
<string name="pref_description_social_recommendations">Recommendations for people to contact
|
|
||||||
based on your message history
|
|
||||||
</string>
|
|
||||||
|
|
||||||
<string name="pref_title_display_name">Display name</string>
|
<string name="pref_title_display_name">Display name</string>
|
||||||
<string name="pref_default_display_name">John Smith</string>
|
<string name="pref_default_display_name">John Smith</string>
|
||||||
|
|
||||||
|
|||||||
4
app/src/main/res/xml/provider_path.xml
Normal file
4
app/src/main/res/xml/provider_path.xml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<paths>
|
||||||
|
<external-path name="external_files" path="."/>
|
||||||
|
</paths>
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
ext {
|
ext {
|
||||||
kotlin_version = '1.9.0'
|
kotlin_version = '1.7.10'
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
|
|||||||
Reference in New Issue
Block a user