mirror of
https://github.com/hmalik144/Farmr.git
synced 2026-01-31 02:41:49 +00:00
Merge branch 'master' into room_database_migration
# Conflicts: # app/build.gradle # app/src/main/java/com/appttude/h_mal/farmr/ui/FragmentAddItem.kt # app/src/main/java/com/appttude/h_mal/farmr/viewmodel/MainViewModel.kt # app/src/test/java/com/appttude/h_mal/farmr/viewmodel/InfoViewModelTest.kt
This commit is contained in:
@@ -39,7 +39,7 @@ commands:
|
|||||||
- android/start-emulator-and-run-tests:
|
- android/start-emulator-and-run-tests:
|
||||||
post-emulator-launch-assemble-command: ./gradlew assembleAndroidTest
|
post-emulator-launch-assemble-command: ./gradlew assembleAndroidTest
|
||||||
test-command: ./gradlew connectedDebugAndroidTest --continue
|
test-command: ./gradlew connectedDebugAndroidTest --continue
|
||||||
system-image: system-images;android-26;google_apis;x86
|
system-image: system-images;android-31;default;x86_64
|
||||||
# store screenshots for failed ui tests
|
# store screenshots for failed ui tests
|
||||||
- when:
|
- when:
|
||||||
condition: on_fail
|
condition: on_fail
|
||||||
@@ -120,6 +120,7 @@ workflows:
|
|||||||
only:
|
only:
|
||||||
- master
|
- master
|
||||||
- release
|
- release
|
||||||
|
- /ui_test.*/
|
||||||
- deploy-to-playstore:
|
- deploy-to-playstore:
|
||||||
context: appttude
|
context: appttude
|
||||||
filters:
|
filters:
|
||||||
@@ -127,4 +128,4 @@ workflows:
|
|||||||
only:
|
only:
|
||||||
- release
|
- release
|
||||||
requires:
|
requires:
|
||||||
- build-and-test
|
- run_instrumentation_test
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -89,6 +89,7 @@ gen-external-apklibs
|
|||||||
.idea/assetWizardSettings.xml
|
.idea/assetWizardSettings.xml
|
||||||
.idea/gradle.xml
|
.idea/gradle.xml
|
||||||
.idea/jarRepositories.xml
|
.idea/jarRepositories.xml
|
||||||
|
.idea/navEditor.xml
|
||||||
|
|
||||||
# Gem/fastlane
|
# Gem/fastlane
|
||||||
Gemfile.lock
|
Gemfile.lock
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
apply plugin: 'org.jetbrains.kotlin.android'
|
apply plugin: 'org.jetbrains.kotlin.android'
|
||||||
|
apply plugin: 'androidx.navigation.safeargs'
|
||||||
apply plugin: 'kotlin-kapt'
|
apply plugin: 'kotlin-kapt'
|
||||||
|
|
||||||
def relStorePassword = System.getenv("RELEASE_STORE_PASSWORD")
|
def relStorePassword = System.getenv("RELEASE_STORE_PASSWORD")
|
||||||
@@ -14,8 +15,8 @@ android {
|
|||||||
applicationId "com.appttude.h_mal.farmr"
|
applicationId "com.appttude.h_mal.farmr"
|
||||||
minSdkVersion MIN_SDK_VERSION
|
minSdkVersion MIN_SDK_VERSION
|
||||||
targetSdkVersion TARGET_SDK_VERSION
|
targetSdkVersion TARGET_SDK_VERSION
|
||||||
versionCode 3
|
versionCode 7
|
||||||
versionName "2.1"
|
versionName "3.0"
|
||||||
testInstrumentationRunner 'com.appttude.h_mal.farmr.application.TestRunner'
|
testInstrumentationRunner 'com.appttude.h_mal.farmr.application.TestRunner'
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
javaCompileOptions {
|
javaCompileOptions {
|
||||||
@@ -60,6 +61,9 @@ dependencies {
|
|||||||
implementation "androidx.lifecycle:lifecycle-livedata-core:$LIFECYCLE_VERSION"
|
implementation "androidx.lifecycle:lifecycle-livedata-core:$LIFECYCLE_VERSION"
|
||||||
implementation "androidx.lifecycle:lifecycle-viewmodel:$LIFECYCLE_VERSION"
|
implementation "androidx.lifecycle:lifecycle-viewmodel:$LIFECYCLE_VERSION"
|
||||||
implementation 'androidx.recyclerview:recyclerview:1.0.0'
|
implementation 'androidx.recyclerview:recyclerview:1.0.0'
|
||||||
|
/ * Fragment Navigation * /
|
||||||
|
implementation "androidx.navigation:navigation-fragment-ktx:$NAVIGATION_VERSION"
|
||||||
|
implementation "androidx.navigation:navigation-ui-ktx:$NAVIGATION_VERSION"
|
||||||
/ * Unit testing * /
|
/ * Unit testing * /
|
||||||
testImplementation "junit:junit:$JUNIT_VERSION"
|
testImplementation "junit:junit:$JUNIT_VERSION"
|
||||||
androidTestRuntimeOnly "org.jetbrains.kotlin:kotlin-test-junit:$KOTLIN_VERSION"
|
androidTestRuntimeOnly "org.jetbrains.kotlin:kotlin-test-junit:$KOTLIN_VERSION"
|
||||||
@@ -97,4 +101,6 @@ dependencies {
|
|||||||
implementation "org.kodein.di:kodein-di-framework-android-core:$KODEIN_VERSION"
|
implementation "org.kodein.di:kodein-di-framework-android-core:$KODEIN_VERSION"
|
||||||
/ * jxl * /
|
/ * jxl * /
|
||||||
implementation "net.sourceforge.jexcelapi:jxl:$JEXCEL_VERSION"
|
implementation "net.sourceforge.jexcelapi:jxl:$JEXCEL_VERSION"
|
||||||
|
/ * calendar view * /
|
||||||
|
implementation 'com.applandeo:material-calendar-view:1.7.0'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ import androidx.test.espresso.matcher.RootMatchers.withDecorView
|
|||||||
import androidx.test.espresso.matcher.ViewMatchers
|
import androidx.test.espresso.matcher.ViewMatchers
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
import com.appttude.h_mal.farmr.application.TestAppClass
|
import com.appttude.h_mal.farmr.application.TestAppClass
|
||||||
|
import com.appttude.h_mal.farmr.ui.utils.EspressoHelper.waitFor
|
||||||
|
import com.appttude.h_mal.farmr.ui.utils.generateShifts
|
||||||
import com.appttude.h_mal.farmr.ui.utils.getShifts
|
import com.appttude.h_mal.farmr.ui.utils.getShifts
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.hamcrest.Matcher
|
import org.hamcrest.Matcher
|
||||||
@@ -73,16 +75,6 @@ open class BaseTest<A : Activity>(
|
|||||||
open fun afterLaunch() {}
|
open fun afterLaunch() {}
|
||||||
open fun testFinished() {}
|
open fun testFinished() {}
|
||||||
|
|
||||||
fun waitFor(delay: Long) {
|
|
||||||
Espresso.onView(ViewMatchers.isRoot()).perform(object : ViewAction {
|
|
||||||
override fun getConstraints(): Matcher<View> = ViewMatchers.isRoot()
|
|
||||||
override fun getDescription(): String = "wait for $delay milliseconds"
|
|
||||||
override fun perform(uiController: UiController, v: View?) {
|
|
||||||
uiController.loopMainThreadForAtLeast(delay)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
fun checkToastMessage(message: String) {
|
fun checkToastMessage(message: String) {
|
||||||
Espresso.onView(ViewMatchers.withText(message)).inRoot(withDecorView(Matchers.not(decorView)))
|
Espresso.onView(ViewMatchers.withText(message)).inRoot(withDecorView(Matchers.not(decorView)))
|
||||||
@@ -95,7 +87,7 @@ open class BaseTest<A : Activity>(
|
|||||||
fun navigateBack() = Espresso.pressBack()
|
fun navigateBack() = Espresso.pressBack()
|
||||||
|
|
||||||
fun addRandomShifts() {
|
fun addRandomShifts() {
|
||||||
testApp.addShiftsToDatabase(getShifts())
|
testApp.addShiftsToDatabase(generateShifts())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clearDataBase() = testApp.clearDatabase()
|
fun clearDataBase() = testApp.clearDatabase()
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import androidx.test.espresso.contrib.RecyclerViewActions
|
|||||||
import androidx.test.espresso.matcher.RootMatchers.isDialog
|
import androidx.test.espresso.matcher.RootMatchers.isDialog
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.*
|
import androidx.test.espresso.matcher.ViewMatchers.*
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import com.appttude.h_mal.farmr.R
|
||||||
import com.appttude.h_mal.farmr.ui.utils.EspressoHelper.waitForView
|
import com.appttude.h_mal.farmr.ui.utils.EspressoHelper.waitForView
|
||||||
import org.hamcrest.CoreMatchers.allOf
|
import org.hamcrest.CoreMatchers.allOf
|
||||||
import org.hamcrest.CoreMatchers.anything
|
import org.hamcrest.CoreMatchers.anything
|
||||||
@@ -58,6 +59,8 @@ open class BaseTestRobot {
|
|||||||
|
|
||||||
fun matchText(resId: Int, text: String): ViewInteraction = matchText(matchView(resId), text)
|
fun matchText(resId: Int, text: String): ViewInteraction = matchText(matchView(resId), text)
|
||||||
|
|
||||||
|
fun scrollTo(viewId: Int): ViewInteraction = matchView(viewId).perform(ViewActions.scrollTo())
|
||||||
|
|
||||||
fun clickListItem(listRes: Int, position: Int) {
|
fun clickListItem(listRes: Int, position: Int) {
|
||||||
onData(anything())
|
onData(anything())
|
||||||
.inAdapterView(allOf(withId(listRes)))
|
.inAdapterView(allOf(withId(listRes)))
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package com.appttude.h_mal.farmr.ui.robots
|
||||||
|
|
||||||
|
import androidx.test.espresso.Espresso.onView
|
||||||
|
import androidx.test.espresso.action.ViewActions.click
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.hasTextColor
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||||
|
import com.appttude.h_mal.farmr.R
|
||||||
|
import com.appttude.h_mal.farmr.base.BaseRecyclerAdapter.CurrentViewHolder
|
||||||
|
import com.appttude.h_mal.farmr.ui.BaseTestRobot
|
||||||
|
import org.hamcrest.core.AllOf.allOf
|
||||||
|
import org.hamcrest.core.IsNot.not
|
||||||
|
|
||||||
|
fun calendarScreen(func: CalendarScreenRobot.() -> Unit) = CalendarScreenRobot().apply { func() }
|
||||||
|
class CalendarScreenRobot : BaseTestRobot() {
|
||||||
|
|
||||||
|
fun clickOnListItemWithText(text: String) =
|
||||||
|
clickOnRecyclerItemWithText<CurrentViewHolder>(R.id.shifts_available_recycler, text)
|
||||||
|
|
||||||
|
fun clickOnListItemAtPosition(position: Int) =
|
||||||
|
clickRecyclerAtPosition<CurrentViewHolder>(R.id.shifts_available_recycler, position)
|
||||||
|
|
||||||
|
fun clickOnEditForItem(position: Int) {
|
||||||
|
clickViewInRecyclerAtPosition<CurrentViewHolder>(
|
||||||
|
R.id.shifts_available_recycler,
|
||||||
|
position,
|
||||||
|
R.id.imageView
|
||||||
|
)
|
||||||
|
onView(withId(R.id.update)).perform(click())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clickOnDeleteForItem(position: Int) {
|
||||||
|
clickViewInRecyclerAtPosition<CurrentViewHolder>(
|
||||||
|
R.id.shifts_available_recycler,
|
||||||
|
position,
|
||||||
|
R.id.imageView
|
||||||
|
)
|
||||||
|
onView(withId(R.id.delete)).perform(click())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clickOnCalendarDay(day: Int) {
|
||||||
|
onView(
|
||||||
|
allOf(
|
||||||
|
withId(R.id.dayLabel),
|
||||||
|
not(hasTextColor(com.applandeo.materialcalendarview.R.color.nextMonthDayColor)),
|
||||||
|
withText("$day"),
|
||||||
|
isDisplayed()
|
||||||
|
)
|
||||||
|
).perform(click())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clickNextMonth() = clickButton(com.applandeo.materialcalendarview.R.id.forwardButton)
|
||||||
|
fun clickPreviousMonth() = clickButton(com.applandeo.materialcalendarview.R.id.previousButton)
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.appttude.h_mal.farmr.ui.robots
|
||||||
|
|
||||||
|
import androidx.test.espresso.action.ViewActions.scrollTo
|
||||||
|
import com.appttude.h_mal.farmr.R
|
||||||
|
import com.appttude.h_mal.farmr.model.ShiftType
|
||||||
|
import com.appttude.h_mal.farmr.ui.BaseTestRobot
|
||||||
|
|
||||||
|
fun furtherInfoScreen(func: FurtherInfoScreenRobot.() -> Unit) = FurtherInfoScreenRobot().apply { func() }
|
||||||
|
class FurtherInfoScreenRobot : BaseTestRobot() {
|
||||||
|
fun assertShiftType(type: ShiftType) {
|
||||||
|
matchText(R.id.details_shift, type.type)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assertDescription(details: String) = matchText(R.id.details_desc, details)
|
||||||
|
|
||||||
|
fun assertDate(date: String) = matchText(R.id.details_date, date)
|
||||||
|
|
||||||
|
fun assertTime(time: String) = matchText(R.id.details_time, time)
|
||||||
|
|
||||||
|
fun assertBreak(breakSummary: String) = matchText(R.id.details_breaks, breakSummary)
|
||||||
|
|
||||||
|
fun assertDuration(duration: String) = matchText(R.id.details_duration, duration)
|
||||||
|
|
||||||
|
fun assertUnits(units: String) = fillEditText(R.id.details_units, units)
|
||||||
|
fun assertRateOfPay(rateOfPay: String) = matchText(R.id.details_pay_rate, rateOfPay)
|
||||||
|
|
||||||
|
fun assertTotalPay(text: String?) = fillEditText(R.id.details_totalpay, text)
|
||||||
|
|
||||||
|
fun update() {
|
||||||
|
matchView(R.id.details_edit).perform(scrollTo())
|
||||||
|
clickButton(R.id.details_edit)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
package com.appttude.h_mal.farmr.ui.robots
|
package com.appttude.h_mal.farmr.ui.robots
|
||||||
|
|
||||||
|
import androidx.test.espresso.Espresso
|
||||||
|
import androidx.test.espresso.action.ViewActions
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers
|
||||||
import com.appttude.h_mal.farmr.R
|
import com.appttude.h_mal.farmr.R
|
||||||
import com.appttude.h_mal.farmr.base.BaseRecyclerAdapter.CurrentViewHolder
|
|
||||||
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.ui.BaseTestRobot
|
import com.appttude.h_mal.farmr.ui.BaseTestRobot
|
||||||
@@ -9,9 +11,6 @@ import com.appttude.h_mal.farmr.ui.BaseTestRobot
|
|||||||
fun homeScreen(func: HomeScreenRobot.() -> Unit) = HomeScreenRobot().apply { func() }
|
fun homeScreen(func: HomeScreenRobot.() -> Unit) = HomeScreenRobot().apply { func() }
|
||||||
class HomeScreenRobot : BaseTestRobot() {
|
class HomeScreenRobot : BaseTestRobot() {
|
||||||
|
|
||||||
fun clickOnItemWithText(text: String) = clickOnRecyclerItemWithText<CurrentViewHolder>(R.id.list_item_view, text)
|
|
||||||
fun clickOnItemAtPosition(position: Int) = clickRecyclerAtPosition<CurrentViewHolder>(R.id.list_item_view, position)
|
|
||||||
fun clickOnEdit(position: Int) = clickViewInRecyclerAtPosition<CurrentViewHolder>(R.id.list_item_view, position, R.id.imageView)
|
|
||||||
fun clickFab() = clickButton(R.id.fab1)
|
fun clickFab() = clickButton(R.id.fab1)
|
||||||
fun clickOnInfoIcon() = clickButton(R.id.action_favorite)
|
fun clickOnInfoIcon() = clickButton(R.id.action_favorite)
|
||||||
fun clickFilterInMenu() = clickOnMenuItem(R.string.filter)
|
fun clickFilterInMenu() = clickOnMenuItem(R.string.filter)
|
||||||
@@ -25,4 +24,16 @@ class HomeScreenRobot : BaseTestRobot() {
|
|||||||
val orderLabel = order.label
|
val orderLabel = order.label
|
||||||
clickDialogButton(orderLabel)
|
clickDialogButton(orderLabel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun clickTab(tab: Tab) {
|
||||||
|
val id = when (tab) {
|
||||||
|
Tab.LIST -> R.id.nav_list
|
||||||
|
Tab.CALENDAR -> R.id.nav_calendar
|
||||||
|
}
|
||||||
|
Espresso.onView(ViewMatchers.withId(id)).perform(ViewActions.click())
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Tab {
|
||||||
|
LIST, CALENDAR
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package com.appttude.h_mal.farmr.ui.robots
|
||||||
|
|
||||||
|
import androidx.test.espresso.Espresso.onView
|
||||||
|
import androidx.test.espresso.action.ViewActions.click
|
||||||
|
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||||
|
import androidx.test.espresso.matcher.RootMatchers.isDialog
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.hasChildCount
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||||
|
import com.appttude.h_mal.farmr.R
|
||||||
|
import com.appttude.h_mal.farmr.base.BaseRecyclerAdapter.CurrentViewHolder
|
||||||
|
import com.appttude.h_mal.farmr.ui.BaseTestRobot
|
||||||
|
import com.appttude.h_mal.farmr.ui.utils.EspressoHelper
|
||||||
|
import com.appttude.h_mal.farmr.ui.utils.EspressoHelper.waitFor
|
||||||
|
|
||||||
|
fun listScreen(func: ListScreenRobot.() -> Unit) = ListScreenRobot().apply { func() }
|
||||||
|
class ListScreenRobot : BaseTestRobot() {
|
||||||
|
|
||||||
|
fun clickOnItemWithText(text: String) =
|
||||||
|
clickOnRecyclerItemWithText<CurrentViewHolder>(R.id.list_item_view, text)
|
||||||
|
|
||||||
|
fun clickOnItemAtPosition(position: Int) =
|
||||||
|
clickRecyclerAtPosition<CurrentViewHolder>(R.id.list_item_view, position)
|
||||||
|
|
||||||
|
fun clickOnEditForItem(position: Int) {
|
||||||
|
clickViewInRecyclerAtPosition<CurrentViewHolder>(
|
||||||
|
R.id.list_item_view,
|
||||||
|
position,
|
||||||
|
R.id.imageView
|
||||||
|
)
|
||||||
|
waitFor(800)
|
||||||
|
EspressoHelper.waitForView(withText("Update Shift")).perform(click())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clickOnDeleteForItem(position: Int) {
|
||||||
|
clickViewInRecyclerAtPosition<CurrentViewHolder>(
|
||||||
|
R.id.list_item_view,
|
||||||
|
position,
|
||||||
|
R.id.imageView
|
||||||
|
)
|
||||||
|
waitFor(800)
|
||||||
|
EspressoHelper.waitForView(withText("Delete Shift")).perform(click())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun confirmDeleteItemOnDialog() {
|
||||||
|
onView(withText("delete"))
|
||||||
|
.inRoot(isDialog())
|
||||||
|
.check(matches(isDisplayed()))
|
||||||
|
.perform(click())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assertListCount(count: Int) =
|
||||||
|
matchView(R.id.list_item_view).check(matches(hasChildCount(count)))
|
||||||
|
}
|
||||||
@@ -23,9 +23,9 @@ class ViewItemScreenRobot : BaseTestRobot() {
|
|||||||
matchText(R.id.details_time, "$timeIn-$timeOut")
|
matchText(R.id.details_time, "$timeIn-$timeOut")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun matchBreakTime(mins: Int) = matchText(R.id.details_breaks, mins.toString())
|
fun matchBreakTime(mins: Int) = matchText(R.id.details_breaks, "$mins mins")
|
||||||
fun matchUnits(units: Float) = fillEditText(R.id.details_units, units.toString())
|
fun matchUnits(units: Float) = matchText(R.id.details_units, units.toString())
|
||||||
fun matchRateOfPay(rateOfPay: Float) = fillEditText(R.id.details_pay_rate, rateOfPay.toString())
|
fun matchRateOfPay(rateOfPay: Float) = matchText(R.id.details_pay_rate, rateOfPay.toString())
|
||||||
fun matchTotalPay(pay: String) = matchText(R.id.details_totalpay, pay)
|
fun matchTotalPay(pay: String) = matchText(R.id.details_totalpay, pay)
|
||||||
fun matchDuration(duration: String) = matchText(R.id.details_duration, duration)
|
fun matchDuration(duration: String) = matchText(R.id.details_duration, duration)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.appttude.h_mal.farmr.ui.tests
|
||||||
|
|
||||||
|
import com.appttude.h_mal.farmr.ui.BaseTest
|
||||||
|
import com.appttude.h_mal.farmr.ui.MainActivity
|
||||||
|
import com.appttude.h_mal.farmr.ui.robots.homeScreen
|
||||||
|
import org.junit.Ignore
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
@Ignore
|
||||||
|
class DummyShiftTests : BaseTest<MainActivity>(MainActivity::class.java) {
|
||||||
|
|
||||||
|
override fun afterLaunch() {
|
||||||
|
super.afterLaunch()
|
||||||
|
addRandomShifts()
|
||||||
|
|
||||||
|
// Content resolver hard to mock
|
||||||
|
// Dirty technique to have a populated list
|
||||||
|
homeScreen {
|
||||||
|
clickFab()
|
||||||
|
navigateBack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a shift successfully
|
||||||
|
@Test
|
||||||
|
fun openAddScreen_addNewHourlyShift_assertShiftDetail() {
|
||||||
|
homeScreen {
|
||||||
|
clickFab()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,25 @@
|
|||||||
package com.appttude.h_mal.farmr.ui.tests
|
package com.appttude.h_mal.farmr.ui.tests
|
||||||
|
|
||||||
|
import androidx.test.espresso.action.ViewActions
|
||||||
|
import com.appttude.h_mal.farmr.R
|
||||||
import com.appttude.h_mal.farmr.model.Order
|
import com.appttude.h_mal.farmr.model.Order
|
||||||
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.ui.BaseTest
|
import com.appttude.h_mal.farmr.ui.BaseTest
|
||||||
import com.appttude.h_mal.farmr.ui.MainActivity
|
import com.appttude.h_mal.farmr.ui.MainActivity
|
||||||
|
import com.appttude.h_mal.farmr.ui.robots.HomeScreenRobot
|
||||||
import com.appttude.h_mal.farmr.ui.robots.addScreen
|
import com.appttude.h_mal.farmr.ui.robots.addScreen
|
||||||
|
import com.appttude.h_mal.farmr.ui.robots.calendarScreen
|
||||||
import com.appttude.h_mal.farmr.ui.robots.filterScreen
|
import com.appttude.h_mal.farmr.ui.robots.filterScreen
|
||||||
import com.appttude.h_mal.farmr.ui.robots.homeScreen
|
import com.appttude.h_mal.farmr.ui.robots.homeScreen
|
||||||
|
import com.appttude.h_mal.farmr.ui.robots.listScreen
|
||||||
import com.appttude.h_mal.farmr.ui.robots.viewScreen
|
import com.appttude.h_mal.farmr.ui.robots.viewScreen
|
||||||
|
import com.appttude.h_mal.farmr.ui.utils.EspressoHelper.waitFor
|
||||||
|
import org.junit.Ignore
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import java.util.Calendar
|
||||||
|
import java.util.Calendar.MONTH
|
||||||
|
import java.util.Calendar.YEAR
|
||||||
|
|
||||||
class ShiftTests : BaseTest<MainActivity>(MainActivity::class.java) {
|
class ShiftTests : BaseTest<MainActivity>(MainActivity::class.java) {
|
||||||
|
|
||||||
@@ -33,7 +43,7 @@ class ShiftTests : BaseTest<MainActivity>(MainActivity::class.java) {
|
|||||||
|
|
||||||
// Add a shift successfully
|
// Add a shift successfully
|
||||||
@Test
|
@Test
|
||||||
fun openAddScreen_addNewShift_newShiftCreated() {
|
fun openAddScreen_addNewHourlyShift_assertShiftDetail() {
|
||||||
homeScreen {
|
homeScreen {
|
||||||
clickFab()
|
clickFab()
|
||||||
}
|
}
|
||||||
@@ -49,16 +59,25 @@ class ShiftTests : BaseTest<MainActivity>(MainActivity::class.java) {
|
|||||||
assertTotalPay("£20.00")
|
assertTotalPay("£20.00")
|
||||||
submit()
|
submit()
|
||||||
}
|
}
|
||||||
homeScreen {
|
listScreen {
|
||||||
clickOnItemWithText("This is a description")
|
clickOnItemWithText("This is a description")
|
||||||
}
|
}
|
||||||
|
viewScreen {
|
||||||
|
matchDescription("This is a description")
|
||||||
|
matchDate("2023-02-11")
|
||||||
|
matchShiftType(ShiftType.HOURLY)
|
||||||
|
matchTime("12:00", "14:30")
|
||||||
|
matchBreakTime(30)
|
||||||
|
matchRateOfPay(10.0f)
|
||||||
|
matchDuration("2 Hours 0 Minutes (+ 30 minutes break)")
|
||||||
|
matchTotalPay("2.0 Hours @ £10.00 per Hour\nEquals: £20.00")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Edit a shift successfully
|
|
||||||
@Test
|
@Test
|
||||||
fun test2() {
|
fun editShift_newDetailsAdded_assertShiftDetail() {
|
||||||
homeScreen {
|
listScreen {
|
||||||
clickOnEdit(0)
|
clickOnEditForItem(0)
|
||||||
}
|
}
|
||||||
addScreen {
|
addScreen {
|
||||||
setDescription("Edited this shift")
|
setDescription("Edited this shift")
|
||||||
@@ -70,7 +89,7 @@ class ShiftTests : BaseTest<MainActivity>(MainActivity::class.java) {
|
|||||||
assertTotalPay("£40.00")
|
assertTotalPay("£40.00")
|
||||||
submit()
|
submit()
|
||||||
}
|
}
|
||||||
homeScreen {
|
listScreen {
|
||||||
clickOnItemWithText("Edited this shift")
|
clickOnItemWithText("Edited this shift")
|
||||||
}
|
}
|
||||||
viewScreen {
|
viewScreen {
|
||||||
@@ -80,12 +99,13 @@ class ShiftTests : BaseTest<MainActivity>(MainActivity::class.java) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// filter the list with date from
|
|
||||||
@Test
|
@Test
|
||||||
fun test3() {
|
fun applySort_listIsSorted_assertShiftsSortedCorrectly() {
|
||||||
homeScreen {
|
homeScreen {
|
||||||
applySort(Sortable.TYPE, Order.DESCENDING)
|
applySort(Sortable.TYPE, Order.DESCENDING)
|
||||||
clickOnItemAtPosition(0)
|
listScreen {
|
||||||
|
clickOnItemAtPosition(0)
|
||||||
|
}
|
||||||
viewScreen {
|
viewScreen {
|
||||||
matchDescription("Day five")
|
matchDescription("Day five")
|
||||||
matchShiftType(ShiftType.PIECE)
|
matchShiftType(ShiftType.PIECE)
|
||||||
@@ -93,25 +113,26 @@ class ShiftTests : BaseTest<MainActivity>(MainActivity::class.java) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// filter the list with date to
|
|
||||||
@Test
|
@Test
|
||||||
fun test4() {
|
fun applyDateBetweenFilterAndClear_listIsFilteredByDate_assertFilteredResultsCorrectly() {
|
||||||
homeScreen {
|
homeScreen {
|
||||||
clickFilterInMenu()
|
clickFilterInMenu()
|
||||||
}
|
}
|
||||||
filterScreen {
|
filterScreen {
|
||||||
setDateIn(2023,8,3)
|
val calendar = Calendar.getInstance()
|
||||||
setDateOut(2023,8,6)
|
val year = calendar.get(YEAR)
|
||||||
|
val month = calendar.get(MONTH) + 1
|
||||||
|
setDateIn(year, month, 3)
|
||||||
|
setDateOut(year, month, 6)
|
||||||
submit()
|
submit()
|
||||||
}
|
}
|
||||||
homeScreen {
|
listScreen {
|
||||||
clickOnItemAtPosition(0)
|
assertListCount(4)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a shift as piece rate
|
|
||||||
@Test
|
@Test
|
||||||
fun test5() {
|
fun openAddScreen_addNewPieceShift_assertShiftDetail() {
|
||||||
homeScreen {
|
homeScreen {
|
||||||
clickFab()
|
clickFab()
|
||||||
}
|
}
|
||||||
@@ -124,18 +145,44 @@ class ShiftTests : BaseTest<MainActivity>(MainActivity::class.java) {
|
|||||||
assertTotalPay("£10.00")
|
assertTotalPay("£10.00")
|
||||||
submit()
|
submit()
|
||||||
}
|
}
|
||||||
homeScreen {
|
listScreen {
|
||||||
clickOnItemWithText("This is a description")
|
clickOnItemWithText("This is a description")
|
||||||
}
|
}
|
||||||
|
viewScreen {
|
||||||
|
matchDescription("This is a description")
|
||||||
|
matchDate("2023-02-11")
|
||||||
|
matchShiftType(ShiftType.PIECE)
|
||||||
|
matchUnits(1f)
|
||||||
|
matchRateOfPay(10.0f)
|
||||||
|
matchTotalPay("1.0 Units @ £10.00 per Unit\nEquals: £10.00")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the details screen
|
@Ignore("Fails in circleci - device size")
|
||||||
@Test
|
@Test
|
||||||
fun test6() {
|
fun openCalendarTab_clickOnFirstActiveDay_assertShiftDetails() {
|
||||||
|
homeScreen {
|
||||||
|
clickTab(HomeScreenRobot.Tab.CALENDAR)
|
||||||
|
}
|
||||||
|
calendarScreen {
|
||||||
|
clickOnCalendarDay(1)
|
||||||
|
scrollTo(R.id.shifts_available_recycler)
|
||||||
|
clickOnListItemAtPosition(0)
|
||||||
|
}
|
||||||
|
viewScreen {
|
||||||
|
matchDate("2023-09-01")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// filter, sort, order and then reset
|
|
||||||
@Test
|
@Test
|
||||||
fun test7() {
|
fun deleteShift_confirmDelete_assertShiftDeleted() {
|
||||||
|
listScreen {
|
||||||
|
clickOnDeleteForItem(0)
|
||||||
|
confirmDeleteItemOnDialog()
|
||||||
|
clickOnItemAtPosition(0)
|
||||||
|
}
|
||||||
|
viewScreen {
|
||||||
|
matchDescription("Day two")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,13 @@ package com.appttude.h_mal.farmr.ui.utils
|
|||||||
|
|
||||||
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.utils.DATE_FORMAT
|
||||||
|
import com.appttude.h_mal.farmr.utils.TIME_FORMAT
|
||||||
|
import com.appttude.h_mal.farmr.utils.getTimeString
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Calendar
|
||||||
|
import java.util.Calendar.DAY_OF_MONTH
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
fun getShifts() = listOf(
|
fun getShifts() = listOf(
|
||||||
Shift(
|
Shift(
|
||||||
@@ -100,4 +107,113 @@ fun getShifts() = listOf(
|
|||||||
10f,
|
10f,
|
||||||
10f
|
10f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun Calendar.setDayAndGetDateString(day: Int): String {
|
||||||
|
set(Calendar.DAY_OF_MONTH, day)
|
||||||
|
val format = SimpleDateFormat(DATE_FORMAT, Locale.getDefault())
|
||||||
|
return format.format(time)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun generateShifts(): List<Shift> {
|
||||||
|
val calendar: Calendar = Calendar.getInstance()
|
||||||
|
|
||||||
|
return listOf(
|
||||||
|
Shift(
|
||||||
|
ShiftType.HOURLY,
|
||||||
|
"Day one",
|
||||||
|
calendar.setDayAndGetDateString(1),
|
||||||
|
"12:00",
|
||||||
|
"13:00",
|
||||||
|
1f,
|
||||||
|
0,
|
||||||
|
0f,
|
||||||
|
10f,
|
||||||
|
10f
|
||||||
|
),
|
||||||
|
Shift(
|
||||||
|
ShiftType.HOURLY,
|
||||||
|
"Day two",
|
||||||
|
calendar.setDayAndGetDateString(2),
|
||||||
|
"12:00",
|
||||||
|
"13:00",
|
||||||
|
1f,
|
||||||
|
0,
|
||||||
|
0f,
|
||||||
|
10f,
|
||||||
|
10f
|
||||||
|
),
|
||||||
|
Shift(
|
||||||
|
ShiftType.HOURLY,
|
||||||
|
"Day three",
|
||||||
|
calendar.setDayAndGetDateString(3),
|
||||||
|
"12:00",
|
||||||
|
"13:00",
|
||||||
|
1f,
|
||||||
|
30,
|
||||||
|
0f,
|
||||||
|
10f,
|
||||||
|
5f
|
||||||
|
),
|
||||||
|
Shift(
|
||||||
|
ShiftType.HOURLY,
|
||||||
|
"Day four",
|
||||||
|
calendar.setDayAndGetDateString(4),
|
||||||
|
"12:00",
|
||||||
|
"13:00",
|
||||||
|
1f,
|
||||||
|
30,
|
||||||
|
0f,
|
||||||
|
10f,
|
||||||
|
5f
|
||||||
|
),
|
||||||
|
Shift(
|
||||||
|
ShiftType.PIECE,
|
||||||
|
"Day five",
|
||||||
|
calendar.setDayAndGetDateString(5),
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
0f,
|
||||||
|
0,
|
||||||
|
1f,
|
||||||
|
10f,
|
||||||
|
10f
|
||||||
|
),
|
||||||
|
Shift(
|
||||||
|
ShiftType.PIECE,
|
||||||
|
"Day six",
|
||||||
|
calendar.setDayAndGetDateString(6),
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
0f,
|
||||||
|
0,
|
||||||
|
1f,
|
||||||
|
10f,
|
||||||
|
10f
|
||||||
|
),
|
||||||
|
Shift(
|
||||||
|
ShiftType.PIECE,
|
||||||
|
"Day seven",
|
||||||
|
calendar.setDayAndGetDateString(7),
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
0f,
|
||||||
|
0,
|
||||||
|
1f,
|
||||||
|
10f,
|
||||||
|
10f
|
||||||
|
),
|
||||||
|
Shift(
|
||||||
|
ShiftType.PIECE,
|
||||||
|
"Day eight",
|
||||||
|
calendar.setDayAndGetDateString(8),
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
0f,
|
||||||
|
0,
|
||||||
|
1f,
|
||||||
|
10f,
|
||||||
|
10f
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -4,11 +4,13 @@ import android.os.SystemClock.sleep
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.CheckBox
|
import android.widget.CheckBox
|
||||||
import android.widget.Checkable
|
import android.widget.Checkable
|
||||||
|
import androidx.test.espresso.Espresso
|
||||||
import androidx.test.espresso.Espresso.onView
|
import androidx.test.espresso.Espresso.onView
|
||||||
import androidx.test.espresso.NoMatchingViewException
|
import androidx.test.espresso.NoMatchingViewException
|
||||||
import androidx.test.espresso.UiController
|
import androidx.test.espresso.UiController
|
||||||
import androidx.test.espresso.ViewAction
|
import androidx.test.espresso.ViewAction
|
||||||
import androidx.test.espresso.ViewInteraction
|
import androidx.test.espresso.ViewInteraction
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.isRoot
|
import androidx.test.espresso.matcher.ViewMatchers.isRoot
|
||||||
import androidx.test.espresso.util.TreeIterables
|
import androidx.test.espresso.util.TreeIterables
|
||||||
import org.hamcrest.BaseMatcher
|
import org.hamcrest.BaseMatcher
|
||||||
@@ -120,4 +122,14 @@ object EspressoHelper {
|
|||||||
|
|
||||||
throw Exception("Error finding a view matching $viewMatcher")
|
throw Exception("Error finding a view matching $viewMatcher")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun waitFor(delay: Long) {
|
||||||
|
onView(isRoot()).perform(object : ViewAction {
|
||||||
|
override fun getConstraints(): Matcher<View> = isRoot()
|
||||||
|
override fun getDescription(): String = "wait for $delay milliseconds"
|
||||||
|
override fun perform(uiController: UiController, v: View?) {
|
||||||
|
uiController.loopMainThreadForAtLeast(delay)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -29,13 +29,6 @@ abstract class BaseFragment<V : BaseViewModel>(@LayoutRes contentLayoutId: Int)
|
|||||||
|
|
||||||
var mActivity: BaseActivity? = null
|
var mActivity: BaseActivity? = null
|
||||||
|
|
||||||
private var shortAnimationDuration by Delegates.notNull<Int>()
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
shortAnimationDuration = resources.getInteger(android.R.integer.config_shortAnimTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
mActivity = requireActivity() as BaseActivity
|
mActivity = requireActivity() as BaseActivity
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import com.appttude.h_mal.farmr.utils.show
|
|||||||
abstract class BaseListAdapter<T : Any>(
|
abstract class BaseListAdapter<T : Any>(
|
||||||
diff: DiffUtil.ItemCallback<T>,
|
diff: DiffUtil.ItemCallback<T>,
|
||||||
private val layoutId: Int,
|
private val layoutId: Int,
|
||||||
private val emptyView: View
|
private val emptyView: View?
|
||||||
) : ListAdapter<T, BaseListAdapter.CurrentViewHolder>(diff) {
|
) : ListAdapter<T, BaseListAdapter.CurrentViewHolder>(diff) {
|
||||||
|
|
||||||
override fun onCreateViewHolder(
|
override fun onCreateViewHolder(
|
||||||
@@ -49,8 +49,8 @@ abstract class BaseListAdapter<T : Any>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun checkEmpty() {
|
fun checkEmpty() {
|
||||||
if (itemCount == 0) emptyView.show()
|
if (itemCount == 0) emptyView?.show()
|
||||||
else emptyView.hide()
|
else emptyView?.hide()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package com.appttude.h_mal.farmr.base
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import androidx.annotation.LayoutRes
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.navigation.NavDirections
|
||||||
|
import com.appttude.h_mal.farmr.model.ViewState
|
||||||
|
import com.appttude.h_mal.farmr.utils.getGenericClassAt
|
||||||
|
import com.appttude.h_mal.farmr.utils.navigateTo
|
||||||
|
import com.appttude.h_mal.farmr.viewmodel.ApplicationViewModelFactory
|
||||||
|
import org.kodein.di.KodeinAware
|
||||||
|
import org.kodein.di.android.x.kodein
|
||||||
|
import org.kodein.di.generic.instance
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
@Suppress("EmptyMethod")
|
||||||
|
abstract class ChildFragment<V : BaseViewModel>(@LayoutRes contentLayoutId: Int) :
|
||||||
|
Fragment(contentLayoutId), KodeinAware {
|
||||||
|
|
||||||
|
override val kodein by kodein()
|
||||||
|
private val factory by instance<ApplicationViewModelFactory>()
|
||||||
|
|
||||||
|
lateinit var viewModel: V
|
||||||
|
|
||||||
|
private val parent by lazy { requireParentFragment().requireParentFragment() }
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
viewModel =
|
||||||
|
ViewModelProvider(parent, factory)[getGenericClassAt<V>(0).java]
|
||||||
|
configureObserver()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun configureObserver() {
|
||||||
|
viewModel.uiState.observe(viewLifecycleOwner) {
|
||||||
|
when (it) {
|
||||||
|
is ViewState.HasStarted -> onStarted()
|
||||||
|
is ViewState.HasData<*> -> onSuccess(it.data)
|
||||||
|
is ViewState.HasError<*> -> onFailure(it.error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called in case of starting operation liveData in viewModel
|
||||||
|
*/
|
||||||
|
open fun onStarted() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called in case of success or some data emitted from the liveData in viewModel
|
||||||
|
*/
|
||||||
|
open fun onSuccess(data: Any?) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called in case of failure or some error emitted from the liveData in viewModel
|
||||||
|
*/
|
||||||
|
open fun onFailure(error: Any?) {}
|
||||||
|
|
||||||
|
|
||||||
|
fun navigateParent(navArg: Any) {
|
||||||
|
when(navArg) {
|
||||||
|
is Int -> (parent).navigateTo(navArg)
|
||||||
|
is NavDirections -> (parent).navigateTo(navArg)
|
||||||
|
else -> { throw IOException("${navArg::class} is not a valid navigation argment") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setTitle(title: String) {
|
||||||
|
(parent as BaseFragment<*>).setTitle(title)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package com.appttude.h_mal.farmr.base
|
||||||
|
|
||||||
|
import android.text.Editable
|
||||||
|
import android.text.TextWatcher
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.EditText
|
||||||
|
import androidx.annotation.LayoutRes
|
||||||
|
import androidx.core.view.children
|
||||||
|
|
||||||
|
|
||||||
|
open class FormFragment<V : BaseViewModel>(@LayoutRes contentLayoutId: Int) : BaseFragment<V>(contentLayoutId) {
|
||||||
|
private val initialFormData = mutableMapOf<Int, String>()
|
||||||
|
private val formData = mutableMapOf<Int, String>()
|
||||||
|
|
||||||
|
fun applyFormListener(view: ViewGroup) {
|
||||||
|
view.children.forEach {
|
||||||
|
if (it is EditText) {
|
||||||
|
initialFormData[it.id] = it.text.trim().toString()
|
||||||
|
setDataInMap(it.id, it.text.trim().toString())
|
||||||
|
it.addCustomTextWatch()
|
||||||
|
} else if (it is ViewGroup) {
|
||||||
|
applyFormListener(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun didFormChange(): Boolean {
|
||||||
|
return !(initialFormData.all { (k, v) ->
|
||||||
|
formData[k] == v
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun EditText.addCustomTextWatch() {
|
||||||
|
addTextChangedListener(object : TextWatcher{
|
||||||
|
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { }
|
||||||
|
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
|
||||||
|
setDataInMap(id, p0.toString())
|
||||||
|
}
|
||||||
|
override fun afterTextChanged(p0: Editable?) { }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setDataInMap(id: Int, text: String) {
|
||||||
|
formData[id] = text
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,5 +22,5 @@ interface Repository {
|
|||||||
timeIn: String?,
|
timeIn: String?,
|
||||||
timeOut: String?,
|
timeOut: String?,
|
||||||
type: String?
|
type: String?
|
||||||
)
|
): Boolean
|
||||||
}
|
}
|
||||||
@@ -91,8 +91,8 @@ class RepositoryImpl(
|
|||||||
timeIn: String?,
|
timeIn: String?,
|
||||||
timeOut: String?,
|
timeOut: String?,
|
||||||
type: String?
|
type: String?
|
||||||
) {
|
): Boolean {
|
||||||
preferenceProvider.saveFilteringDetails(description, timeIn, timeOut, type)
|
return preferenceProvider.saveFilteringDetails(description, timeIn, timeOut, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -44,13 +44,13 @@ class PreferenceProvider(
|
|||||||
timeIn: String?,
|
timeIn: String?,
|
||||||
timeOut: String?,
|
timeOut: String?,
|
||||||
type: String?
|
type: String?
|
||||||
) {
|
): Boolean {
|
||||||
preference.edit()
|
return preference.edit()
|
||||||
.putString(DESCRIPTION, description)
|
.putString(DESCRIPTION, description)
|
||||||
.putString(DATE_IN, timeIn)
|
.putString(DATE_IN, timeIn)
|
||||||
.putString(DATE_OUT, timeOut)
|
.putString(DATE_OUT, timeOut)
|
||||||
.putString(TYPE, type)
|
.putString(TYPE, type)
|
||||||
.apply()
|
.commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getFilteringDetails(): Map<String, String?> {
|
fun getFilteringDetails(): Map<String, String?> {
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package com.appttude.h_mal.farmr.ui
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.applandeo.materialcalendarview.CalendarView
|
||||||
|
import com.applandeo.materialcalendarview.EventDay
|
||||||
|
import com.appttude.h_mal.farmr.R
|
||||||
|
import com.appttude.h_mal.farmr.base.ChildFragment
|
||||||
|
import com.appttude.h_mal.farmr.data.legacydb.ShiftObject
|
||||||
|
import com.appttude.h_mal.farmr.utils.tryGet
|
||||||
|
import com.appttude.h_mal.farmr.viewmodel.MainViewModel
|
||||||
|
import java.util.Calendar
|
||||||
|
|
||||||
|
class CalendarFragment : ChildFragment<MainViewModel>(R.layout.fragment_calendar) {
|
||||||
|
private lateinit var shiftListView: RecyclerView
|
||||||
|
private lateinit var calendarView: CalendarView
|
||||||
|
|
||||||
|
private lateinit var mAdapter: ShiftListAdapter
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
shiftListView = view.findViewById(R.id.shifts_available_recycler)
|
||||||
|
calendarView = view.findViewById(R.id.calendarView)
|
||||||
|
|
||||||
|
mAdapter = ShiftListAdapter(this, null, viewModel)
|
||||||
|
shiftListView.adapter = mAdapter
|
||||||
|
|
||||||
|
calendarView.setOnDayClickListener { populateShiftListsForDay(it.calendar) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
viewModel.refreshLiveData()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSuccess(data: Any?) {
|
||||||
|
super.onSuccess(data)
|
||||||
|
if (data is List<*>) {
|
||||||
|
val events: List<EventDay>? = viewModel.retrieveEvents()
|
||||||
|
calendarView.setEvents(events)
|
||||||
|
|
||||||
|
tryGet { calendarView.firstSelectedDate }?.let {
|
||||||
|
populateShiftListsForDay(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun populateShiftListsForDay(calendar: Calendar) {
|
||||||
|
val data: List<ShiftObject>? = viewModel.getShiftsOnTheDay(calendar)
|
||||||
|
mAdapter.submitList(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ 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.model.Success
|
||||||
|
import com.appttude.h_mal.farmr.utils.goBack
|
||||||
import com.appttude.h_mal.farmr.utils.setDatePicker
|
import com.appttude.h_mal.farmr.utils.setDatePicker
|
||||||
import com.appttude.h_mal.farmr.viewmodel.FilterViewModel
|
import com.appttude.h_mal.farmr.viewmodel.FilterViewModel
|
||||||
|
|
||||||
@@ -33,7 +34,6 @@ class FilterDataFragment : BaseFragment<FilterViewModel>(R.layout.fragment_filte
|
|||||||
|
|
||||||
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))
|
|
||||||
|
|
||||||
LocationET = view.findViewById(R.id.filterLocationEditText)
|
LocationET = view.findViewById(R.id.filterLocationEditText)
|
||||||
dateFromET = view.findViewById(R.id.fromdateInEditText)
|
dateFromET = view.findViewById(R.id.fromdateInEditText)
|
||||||
@@ -75,6 +75,16 @@ class FilterDataFragment : BaseFragment<FilterViewModel>(R.layout.fragment_filte
|
|||||||
submit.setOnClickListener(this)
|
submit.setOnClickListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setHasOptionsMenu(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
setTitle(getString(R.string.title_activity_filter_data))
|
||||||
|
}
|
||||||
|
|
||||||
override fun onItemSelected(
|
override fun onItemSelected(
|
||||||
parentView: AdapterView<*>?,
|
parentView: AdapterView<*>?,
|
||||||
selectedItemView: View?,
|
selectedItemView: View?,
|
||||||
@@ -100,6 +110,6 @@ class FilterDataFragment : BaseFragment<FilterViewModel>(R.layout.fragment_filte
|
|||||||
|
|
||||||
override fun onSuccess(data: Any?) {
|
override fun onSuccess(data: Any?) {
|
||||||
super.onSuccess(data)
|
super.onSuccess(data)
|
||||||
if (data is Success) popBackStack()
|
if (data is Success) goBack()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
package com.appttude.h_mal.farmr.ui
|
package com.appttude.h_mal.farmr.ui
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
@@ -9,8 +11,10 @@ import android.widget.RadioButton
|
|||||||
import android.widget.RadioGroup
|
import android.widget.RadioGroup
|
||||||
import android.widget.ScrollView
|
import android.widget.ScrollView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import androidx.activity.OnBackPressedCallback
|
||||||
import androidx.core.widget.doAfterTextChanged
|
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.FormFragment
|
||||||
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.room.converters.DateConverter
|
import com.appttude.h_mal.farmr.data.room.converters.DateConverter
|
||||||
@@ -22,16 +26,18 @@ import com.appttude.h_mal.farmr.utils.createDialog
|
|||||||
import com.appttude.h_mal.farmr.utils.displayToast
|
import com.appttude.h_mal.farmr.utils.displayToast
|
||||||
import com.appttude.h_mal.farmr.utils.formatAsCurrencyString
|
import com.appttude.h_mal.farmr.utils.formatAsCurrencyString
|
||||||
import com.appttude.h_mal.farmr.utils.formatToTwoDpString
|
import com.appttude.h_mal.farmr.utils.formatToTwoDpString
|
||||||
|
import com.appttude.h_mal.farmr.utils.goBack
|
||||||
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.setDatePicker
|
import com.appttude.h_mal.farmr.utils.setDatePicker
|
||||||
import com.appttude.h_mal.farmr.utils.setTimePicker
|
import com.appttude.h_mal.farmr.utils.setTimePicker
|
||||||
import com.appttude.h_mal.farmr.utils.show
|
import com.appttude.h_mal.farmr.utils.show
|
||||||
import com.appttude.h_mal.farmr.utils.validateField
|
import com.appttude.h_mal.farmr.utils.validateField
|
||||||
import com.appttude.h_mal.farmr.viewmodel.SubmissionViewModel
|
import com.appttude.h_mal.farmr.viewmodel.SubmissionViewModel
|
||||||
|
|
||||||
class FragmentAddItem : BaseFragment<SubmissionViewModel>(R.layout.fragment_add_item),
|
class FragmentAddItem : FormFragment<SubmissionViewModel>(R.layout.fragment_add_item),
|
||||||
RadioGroup.OnCheckedChangeListener, BackPressedListener {
|
RadioGroup.OnCheckedChangeListener {
|
||||||
|
|
||||||
|
private lateinit var onBackPressed: OnBackPressedCallback
|
||||||
|
|
||||||
private val dateConverter = DateConverter()
|
private val dateConverter = DateConverter()
|
||||||
private val timeConverter = TimeConverter()
|
private val timeConverter = TimeConverter()
|
||||||
@@ -122,61 +128,87 @@ class FragmentAddItem : BaseFragment<SubmissionViewModel>(R.layout.fragment_add_
|
|||||||
setupViewAfterViewCreated()
|
setupViewAfterViewCreated()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupViewAfterViewCreated() {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
id = arguments?.getLong(ID)
|
super.onCreate(savedInstanceState)
|
||||||
wholeView.hide()
|
setHasOptionsMenu(false)
|
||||||
|
// This callback is only called when MyFragment is at least started
|
||||||
val title = when (arguments?.containsKey(ID)) {
|
onBackPressed = object : OnBackPressedCallback(false) {
|
||||||
true -> {
|
override fun handleOnBackPressed() {
|
||||||
// Since we are editing a shift lets load the shift data into the views
|
onBackPressed()
|
||||||
viewModel.getCurrentShift(arguments!!.getLong(ID))?.run {
|
|
||||||
mLocationEditText.setText(description)
|
|
||||||
mDateEditText.setText(dateConverter.fromDate(date))
|
|
||||||
|
|
||||||
// Set types
|
|
||||||
mType = ShiftType.getEnumByType(type)
|
|
||||||
mDescription = description
|
|
||||||
mDate = dateConverter.fromDate(date)
|
|
||||||
mPayRate = payRate!!
|
|
||||||
|
|
||||||
when (ShiftType.getEnumByType(type)) {
|
|
||||||
ShiftType.HOURLY -> {
|
|
||||||
mHourlyRadioButton.isChecked = true
|
|
||||||
mPieceRadioButton.isChecked = false
|
|
||||||
mTimeInEditText.setText(timeConverter.fromTime(timeIn))
|
|
||||||
mTimeOutEditText.setText(timeConverter.fromTime(timeOut))
|
|
||||||
mBreakEditText.setText(breakMins.toString())
|
|
||||||
val durationText = "${duration.formatToTwoDpString()} Hours"
|
|
||||||
mDurationTextView.text = durationText
|
|
||||||
|
|
||||||
// Set fields
|
|
||||||
mTimeIn = timeConverter.fromTime(timeIn)
|
|
||||||
mTimeOut = timeConverter.fromTime(timeOut)
|
|
||||||
mBreaks = breakMins
|
|
||||||
}
|
|
||||||
|
|
||||||
ShiftType.PIECE -> {
|
|
||||||
mHourlyRadioButton.isChecked = false
|
|
||||||
mPieceRadioButton.isChecked = true
|
|
||||||
mUnitEditText.setText(units?.formatToTwoDpString())
|
|
||||||
|
|
||||||
// Set piece rate units
|
|
||||||
mUnits = units
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mPayRateEditText.setText(payRate.formatAsCurrencyString())
|
|
||||||
mTotalPayTextView.text = totalPay?.formatAsCurrencyString()
|
|
||||||
|
|
||||||
calculateTotalPay()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return title
|
|
||||||
getString(R.string.edit_item_title)
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
requireActivity().onBackPressedDispatcher.addCallback(this, onBackPressed)
|
||||||
|
|
||||||
|
id = try {
|
||||||
|
FragmentAddItemArgs.fromBundle(requireArguments()).shiftId
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.i("Nav Args", "Failed to retrieve args from navigation")
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
val title = when (arguments?.containsKey(ID)) {
|
||||||
|
true -> getString(R.string.edit_item_title)
|
||||||
else -> getString(R.string.add_item_title)
|
else -> getString(R.string.add_item_title)
|
||||||
}
|
}
|
||||||
setTitle(title)
|
setTitle(title)
|
||||||
|
|
||||||
|
onBackPressed.isEnabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
onBackPressed.isEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupViewAfterViewCreated() {
|
||||||
|
wholeView.hide()
|
||||||
|
|
||||||
|
// Since we are editing a shift lets load the shift data into the views
|
||||||
|
id?.let { viewModel.getCurrentShift(it) }?.run {
|
||||||
|
mLocationEditText.setText(description)
|
||||||
|
mDateEditText.setText(date)
|
||||||
|
|
||||||
|
// Set types
|
||||||
|
mType = ShiftType.getEnumByType(type)
|
||||||
|
mDescription = description
|
||||||
|
mDate = date
|
||||||
|
mPayRate = rateOfPay
|
||||||
|
|
||||||
|
when (ShiftType.getEnumByType(type)) {
|
||||||
|
ShiftType.HOURLY -> {
|
||||||
|
mHourlyRadioButton.isChecked = true
|
||||||
|
mPieceRadioButton.isChecked = false
|
||||||
|
mTimeInEditText.setText(timeIn)
|
||||||
|
mTimeOutEditText.setText(timeOut)
|
||||||
|
mBreakEditText.setText(breakMins.toString())
|
||||||
|
val durationText = "${duration.formatToTwoDpString()} Hours"
|
||||||
|
mDurationTextView.text = durationText
|
||||||
|
|
||||||
|
// Set fields
|
||||||
|
mTimeIn = timeIn
|
||||||
|
mTimeOut = timeOut
|
||||||
|
mBreaks = breakMins
|
||||||
|
}
|
||||||
|
|
||||||
|
ShiftType.PIECE -> {
|
||||||
|
mHourlyRadioButton.isChecked = false
|
||||||
|
mPieceRadioButton.isChecked = true
|
||||||
|
mUnitEditText.setText(units.formatToTwoDpString())
|
||||||
|
|
||||||
|
// Set piece rate units
|
||||||
|
mUnits = units
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mPayRateEditText.setText(rateOfPay.formatAsCurrencyString())
|
||||||
|
mTotalPayTextView.text = totalPay.formatAsCurrencyString()
|
||||||
|
|
||||||
|
calculateTotalPay()
|
||||||
|
}
|
||||||
|
|
||||||
|
applyFormListener(view = view as ViewGroup)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCheckedChanged(radioGroup: RadioGroup, id: Int) {
|
override fun onCheckedChanged(radioGroup: RadioGroup, id: Int) {
|
||||||
@@ -269,6 +301,7 @@ class FragmentAddItem : BaseFragment<SubmissionViewModel>(R.layout.fragment_add_
|
|||||||
StringBuilder().append(mDuration).append(" hours").toString()
|
StringBuilder().append(mDuration).append(" hours").toString()
|
||||||
mDuration!! * mPayRate
|
mDuration!! * mPayRate
|
||||||
}
|
}
|
||||||
|
|
||||||
ShiftType.PIECE -> {
|
ShiftType.PIECE -> {
|
||||||
(mUnits ?: 0f) * mPayRate
|
(mUnits ?: 0f) * mPayRate
|
||||||
}
|
}
|
||||||
@@ -277,27 +310,26 @@ class FragmentAddItem : BaseFragment<SubmissionViewModel>(R.layout.fragment_add_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBackPressed(): Boolean {
|
fun onBackPressed() {
|
||||||
if (mRadioGroup.checkedRadioButtonId == -1) {
|
if (didFormChange()) {
|
||||||
mActivity?.popBackStack()
|
|
||||||
} else {
|
|
||||||
requireContext().createDialog(
|
requireContext().createDialog(
|
||||||
title = "Discard Changes?",
|
title = "Discard Changes?",
|
||||||
message = "Are you sure you want to discard changes?",
|
message = "Are you sure you want to discard changes?",
|
||||||
displayCancel = true,
|
displayCancel = true,
|
||||||
okCallback = { _, _ ->
|
okCallback = { _, _ ->
|
||||||
mActivity?.popBackStack()
|
goBack()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
goBack()
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSuccess(data: Any?) {
|
override fun onSuccess(data: Any?) {
|
||||||
super.onSuccess(data)
|
super.onSuccess(data)
|
||||||
if (data is Success) {
|
if (data is Success) {
|
||||||
displayToast(data.successMessage)
|
displayToast(data.successMessage)
|
||||||
popBackStack()
|
goBack()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package com.appttude.h_mal.farmr.ui
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.appttude.h_mal.farmr.R
|
||||||
|
import com.appttude.h_mal.farmr.base.ChildFragment
|
||||||
|
import com.appttude.h_mal.farmr.data.legacydb.ShiftObject
|
||||||
|
import com.appttude.h_mal.farmr.model.Success
|
||||||
|
import com.appttude.h_mal.farmr.utils.displayToast
|
||||||
|
import com.appttude.h_mal.farmr.utils.navigateTo
|
||||||
|
import com.appttude.h_mal.farmr.viewmodel.MainViewModel
|
||||||
|
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
|
||||||
|
|
||||||
|
class FragmentList : ChildFragment<MainViewModel>(R.layout.fragment_list) {
|
||||||
|
private lateinit var productListView: RecyclerView
|
||||||
|
private lateinit var emptyView: View
|
||||||
|
private lateinit var mAdapter: ShiftListAdapter
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
emptyView = view.findViewById(R.id.empty_view)
|
||||||
|
productListView = view.findViewById(R.id.list_item_view)
|
||||||
|
|
||||||
|
mAdapter = ShiftListAdapter(this, emptyView, viewModel)
|
||||||
|
productListView.adapter = mAdapter
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
viewModel.refreshLiveData()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSuccess(data: Any?) {
|
||||||
|
super.onSuccess(data)
|
||||||
|
if (data is List<*>) {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
mAdapter.submitList(data as List<ShiftObject>)
|
||||||
|
} else if (data is Success) {
|
||||||
|
displayToast(data.successMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -3,71 +3,85 @@ package com.appttude.h_mal.farmr.ui
|
|||||||
import android.app.AlertDialog
|
import android.app.AlertDialog
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.activity.OnBackPressedCallback
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver
|
import androidx.navigation.ui.setupWithNavController
|
||||||
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.BaseFragment
|
import com.appttude.h_mal.farmr.base.BaseFragment
|
||||||
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.navigateTo
|
||||||
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.MainViewModel
|
||||||
|
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
import java.io.File
|
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) {
|
||||||
private lateinit var productListView: RecyclerView
|
private lateinit var onBackPressed: OnBackPressedCallback
|
||||||
private lateinit var emptyView: View
|
|
||||||
private lateinit var mAdapter: ShiftListAdapter
|
lateinit var navView: BottomNavigationView
|
||||||
|
|
||||||
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)
|
||||||
|
// This callback is only called when MyFragment is at least started
|
||||||
|
onBackPressed = object : OnBackPressedCallback(false) {
|
||||||
|
override fun handleOnBackPressed() {
|
||||||
|
onBackPressed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
requireActivity().onBackPressedDispatcher.addCallback(this, onBackPressed)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
|
||||||
|
onBackPressed.isEnabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
onBackPressed.isEnabled = false
|
||||||
|
|
||||||
|
viewModel.saveBottomBarState(navView.selectedItemId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
emptyView = view.findViewById(R.id.empty_view)
|
navView = view.findViewById(R.id.bottom_bar)
|
||||||
productListView = view.findViewById(R.id.list_item_view)
|
val navHost = childFragmentManager.findFragmentById(R.id.sub_container) as NavHostFragment
|
||||||
|
|
||||||
mAdapter = ShiftListAdapter(this, emptyView) {
|
val navController = navHost.navController
|
||||||
viewModel.deleteShift(it)
|
navController.setGraph(R.navigation.home_navigation)
|
||||||
|
|
||||||
|
navView.setupWithNavController(navController)
|
||||||
|
|
||||||
|
viewModel.getBottomBarState()?.let {
|
||||||
|
navView.selectedItemId = it
|
||||||
|
}
|
||||||
|
|
||||||
|
navController.addOnDestinationChangedListener { _, destination, _ ->
|
||||||
|
setTitle(destination.label.toString())
|
||||||
}
|
}
|
||||||
productListView.adapter = mAdapter
|
|
||||||
|
|
||||||
view.findViewById<FloatingActionButton>(R.id.fab1).setOnClickListener {
|
view.findViewById<FloatingActionButton>(R.id.fab1).setOnClickListener {
|
||||||
navigateToFragment(FragmentAddItem(), name = "additem")
|
navigateTo(R.id.main_to_addItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
super.onStart()
|
// Inflate the menu; this adds items to the action bar if it is present.
|
||||||
viewModel.refreshLiveData()
|
inflater.inflate(R.menu.menu_main, menu)
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSuccess(data: Any?) {
|
|
||||||
super.onSuccess(data)
|
|
||||||
if (data is List<*>) {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
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 {
|
||||||
@@ -87,7 +101,7 @@ class FragmentMain : BaseFragment<MainViewModel>(R.layout.fragment_main), BackPr
|
|||||||
}
|
}
|
||||||
|
|
||||||
R.id.filter_data -> {
|
R.id.filter_data -> {
|
||||||
navigateToFragment(FilterDataFragment(), name = "filterdata")
|
navigateTo(R.id.main_to_filterData)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,21 +184,13 @@ class FragmentMain : BaseFragment<MainViewModel>(R.layout.fragment_main), BackPr
|
|||||||
file
|
file
|
||||||
)
|
)
|
||||||
intent.setDataAndType(excelUri, "application/vnd.ms-excel")
|
intent.setDataAndType(excelUri, "application/vnd.ms-excel")
|
||||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun exportDialog() {
|
fun onBackPressed() {
|
||||||
AlertDialog.Builder(context)
|
|
||||||
.setTitle("Export?")
|
|
||||||
.setMessage("Exporting current filtered data. Continue?")
|
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
|
||||||
.setPositiveButton(android.R.string.ok) { _, _ -> exportData() }.create().show()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBackPressed(): Boolean {
|
|
||||||
requireContext().createDialog(
|
requireContext().createDialog(
|
||||||
title = "Leave?",
|
title = "Leave?",
|
||||||
message = "Are you sure you want to exit Farmr?",
|
message = "Are you sure you want to exit Farmr?",
|
||||||
@@ -198,6 +204,5 @@ class FragmentMain : BaseFragment<MainViewModel>(R.layout.fragment_main), BackPr
|
|||||||
exitProcess(0)
|
exitProcess(0)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12,7 +12,9 @@ import com.appttude.h_mal.farmr.data.legacydb.ShiftObject
|
|||||||
import com.appttude.h_mal.farmr.model.ShiftType
|
import com.appttude.h_mal.farmr.model.ShiftType
|
||||||
import com.appttude.h_mal.farmr.utils.CURRENCY
|
import com.appttude.h_mal.farmr.utils.CURRENCY
|
||||||
import com.appttude.h_mal.farmr.utils.formatAsCurrencyString
|
import com.appttude.h_mal.farmr.utils.formatAsCurrencyString
|
||||||
|
import com.appttude.h_mal.farmr.utils.formatToTwoDp
|
||||||
import com.appttude.h_mal.farmr.utils.hide
|
import com.appttude.h_mal.farmr.utils.hide
|
||||||
|
import com.appttude.h_mal.farmr.utils.navigateTo
|
||||||
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.utils.show
|
||||||
import com.appttude.h_mal.farmr.viewmodel.InfoViewModel
|
import com.appttude.h_mal.farmr.viewmodel.InfoViewModel
|
||||||
@@ -35,7 +37,6 @@ class FurtherInfoFragment : BaseFragment<InfoViewModel>(R.layout.fragment_futher
|
|||||||
|
|
||||||
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.further_info_title))
|
|
||||||
|
|
||||||
progressBarFI = view.findViewById(R.id.progressBar_info)
|
progressBarFI = view.findViewById(R.id.progressBar_info)
|
||||||
wholeView = view.findViewById(R.id.further_info_view)
|
wholeView = view.findViewById(R.id.further_info_view)
|
||||||
@@ -52,11 +53,24 @@ class FurtherInfoFragment : BaseFragment<InfoViewModel>(R.layout.fragment_futher
|
|||||||
hourlyDetailHolder = view.findViewById(R.id.details_hourly_details)
|
hourlyDetailHolder = view.findViewById(R.id.details_hourly_details)
|
||||||
unitsHolder = view.findViewById(R.id.details_units_holder)
|
unitsHolder = view.findViewById(R.id.details_units_holder)
|
||||||
|
|
||||||
|
val id = FurtherInfoFragmentArgs.fromBundle(requireArguments()).shiftId
|
||||||
|
|
||||||
editButton.setOnClickListener {
|
editButton.setOnClickListener {
|
||||||
navigateToFragment(FragmentAddItem(), name = "additem", bundle = arguments!!)
|
val nav = FurtherInfoFragmentDirections.furtherInfoToAddItem(id)
|
||||||
|
navigateTo(nav)
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.retrieveData(arguments)
|
viewModel.retrieveData(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setHasOptionsMenu(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
setTitle(getString(R.string.further_info_title))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSuccess(data: Any?) {
|
override fun onSuccess(data: Any?) {
|
||||||
@@ -91,7 +105,7 @@ class FurtherInfoFragment : BaseFragment<InfoViewModel>(R.layout.fragment_futher
|
|||||||
unitsTV.text = units.toString()
|
unitsTV.text = units.toString()
|
||||||
|
|
||||||
val paymentSummary =
|
val paymentSummary =
|
||||||
StringBuilder().append(units.formatAsCurrencyString()).append(" Units @ ")
|
StringBuilder().append(units.formatToTwoDp()).append(" Units @ ")
|
||||||
.append(rateOfPay.formatAsCurrencyString()).append(" per Unit").append("\n")
|
.append(rateOfPay.formatAsCurrencyString()).append(" per Unit").append("\n")
|
||||||
.append("Equals: ").append(totalPay.formatAsCurrencyString())
|
.append("Equals: ").append(totalPay.formatAsCurrencyString())
|
||||||
totalPayTV.text = paymentSummary
|
totalPayTV.text = paymentSummary
|
||||||
|
|||||||
@@ -1,19 +1,15 @@
|
|||||||
package com.appttude.h_mal.farmr.ui
|
package com.appttude.h_mal.farmr.ui
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.Menu
|
import android.view.MenuItem
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
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.BaseActivity
|
import com.appttude.h_mal.farmr.base.BaseActivity
|
||||||
import com.appttude.h_mal.farmr.utils.popBackStack
|
|
||||||
|
|
||||||
class MainActivity : BaseActivity() {
|
class MainActivity : BaseActivity() {
|
||||||
private lateinit var toolbar: Toolbar
|
private lateinit var toolbar: Toolbar
|
||||||
|
private lateinit var navHost: NavHostFragment
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@@ -21,26 +17,19 @@ class MainActivity : BaseActivity() {
|
|||||||
toolbar = findViewById(R.id.toolbar)
|
toolbar = findViewById(R.id.toolbar)
|
||||||
setSupportActionBar(toolbar)
|
setSupportActionBar(toolbar)
|
||||||
|
|
||||||
val fragmentTransaction = supportFragmentManager.beginTransaction()
|
navHost = supportFragmentManager
|
||||||
fragmentTransaction.replace(R.id.container, FragmentMain()).addToBackStack("main").commit()
|
.findFragmentById(R.id.container) as NavHostFragment
|
||||||
|
val navController = navHost.navController
|
||||||
|
navController.setGraph(R.navigation.shift_navigation)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
// Inflate the menu; this adds items to the action bar if it is present.
|
// Handle action bar item clicks here. The action bar will
|
||||||
menuInflater.inflate(R.menu.menu_main, menu)
|
// automatically handle clicks on the Home/Up button, so long
|
||||||
return true
|
// as you specify a parent activity in AndroidManifest.xml.
|
||||||
}
|
when (item.itemId) {
|
||||||
|
android.R.id.home -> onBackPressed()
|
||||||
override fun onBackPressed() {
|
|
||||||
val currentFragment = supportFragmentManager.findFragmentById(R.id.container)
|
|
||||||
if (currentFragment is BackPressedListener) {
|
|
||||||
currentFragment.onBackPressed()
|
|
||||||
} else {
|
|
||||||
if (supportFragmentManager.backStackEntryCount > 1) {
|
|
||||||
popBackStack()
|
|
||||||
} else {
|
|
||||||
super.onBackPressed()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,24 +2,29 @@ package com.appttude.h_mal.farmr.ui
|
|||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.AlertDialog
|
import android.app.AlertDialog
|
||||||
import android.os.Bundle
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.appcompat.widget.PopupMenu
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import com.appttude.h_mal.farmr.R
|
import com.appttude.h_mal.farmr.R
|
||||||
import com.appttude.h_mal.farmr.base.BaseListAdapter
|
import com.appttude.h_mal.farmr.base.BaseListAdapter
|
||||||
|
import com.appttude.h_mal.farmr.base.ChildFragment
|
||||||
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.ShiftType
|
import com.appttude.h_mal.farmr.model.ShiftType
|
||||||
import com.appttude.h_mal.farmr.utils.ID
|
|
||||||
import com.appttude.h_mal.farmr.utils.formatToTwoDpString
|
import com.appttude.h_mal.farmr.utils.formatToTwoDpString
|
||||||
import com.appttude.h_mal.farmr.utils.navigateToFragment
|
import com.appttude.h_mal.farmr.viewmodel.MainViewModel
|
||||||
|
|
||||||
|
|
||||||
|
const val PIECE_ITEM = 500
|
||||||
|
const val HOURLY_ITEM = 501
|
||||||
|
|
||||||
class ShiftListAdapter(
|
class ShiftListAdapter(
|
||||||
private val fragment: Fragment,
|
private val fragment: ChildFragment<*>,
|
||||||
emptyView: View,
|
emptyView: View?,
|
||||||
private val longPressCallback: (Long) -> Unit
|
private val viewModel: MainViewModel
|
||||||
) : BaseListAdapter<ShiftObject>(diffCallBack, R.layout.list_item_1, emptyView) {
|
) : BaseListAdapter<ShiftObject>(diffCallBack, R.layout.list_item_1, emptyView) {
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
@@ -30,70 +35,91 @@ class ShiftListAdapter(
|
|||||||
val descriptionTextView: TextView = view.findViewById(R.id.location)
|
val descriptionTextView: TextView = view.findViewById(R.id.location)
|
||||||
val dateTextView: TextView = view.findViewById(R.id.date)
|
val dateTextView: TextView = view.findViewById(R.id.date)
|
||||||
val totalPay: TextView = view.findViewById(R.id.total_pay)
|
val totalPay: TextView = view.findViewById(R.id.total_pay)
|
||||||
val hoursView: TextView = view.findViewById(R.id.hours)
|
|
||||||
val h: TextView = view.findViewById(R.id.h)
|
|
||||||
val minutesView: TextView = view.findViewById(R.id.minutes)
|
|
||||||
val m: TextView = view.findViewById(R.id.m)
|
|
||||||
val editView: ImageView = view.findViewById(R.id.imageView)
|
val editView: ImageView = view.findViewById(R.id.imageView)
|
||||||
h.text = "h"
|
|
||||||
m.text = "m"
|
|
||||||
val typeText: String = data.type
|
|
||||||
val descriptionText: String = data.description
|
|
||||||
val dateText: String = data.date
|
|
||||||
val totalPayText: String = data.totalPay.formatToTwoDpString()
|
|
||||||
|
|
||||||
descriptionTextView.text = descriptionText
|
when (getItemViewType(position)) {
|
||||||
dateTextView.text = dateText
|
HOURLY_ITEM -> {
|
||||||
totalPay.text = totalPayText
|
val hoursView: TextView = view.findViewById(R.id.hours)
|
||||||
|
val minutesView: TextView = view.findViewById(R.id.minutes)
|
||||||
|
|
||||||
when (ShiftType.getEnumByType(typeText)) {
|
|
||||||
ShiftType.HOURLY -> {
|
|
||||||
val time = data.getHoursMinutesPairFromDuration()
|
val time = data.getHoursMinutesPairFromDuration()
|
||||||
|
|
||||||
hoursView.text = time.first
|
hoursView.text = time.first
|
||||||
minutesView.text = time.second
|
minutesView.text = if (time.second.length == 1) "0${time.second}" else time.second
|
||||||
}
|
}
|
||||||
|
|
||||||
ShiftType.PIECE -> {
|
PIECE_ITEM -> {
|
||||||
|
val unitsView: TextView = view.findViewById(R.id.pieces)
|
||||||
val unitsText: String = data.units.toString()
|
val unitsText: String = data.units.toString()
|
||||||
|
|
||||||
hoursView.text = unitsText
|
unitsView.text = unitsText
|
||||||
h.text = ""
|
|
||||||
minutesView.text = ""
|
|
||||||
m.text = "pcs"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
descriptionTextView.text = data.description
|
||||||
|
dateTextView.text = data.date
|
||||||
|
totalPay.text = data.totalPay.formatToTwoDpString()
|
||||||
|
|
||||||
val b: Bundle = Bundle()
|
|
||||||
b.putLong(ID, data.id)
|
|
||||||
view.setOnClickListener {
|
view.setOnClickListener {
|
||||||
// Navigate to further info
|
// Navigate to further info
|
||||||
fragment.navigateToFragment(
|
val nav = FragmentMainDirections.mainToFurtherInfo(data.id)
|
||||||
FurtherInfoFragment(),
|
fragment.navigateParent(nav)
|
||||||
bundle = b,
|
|
||||||
name = "furtherinfo"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
editView.setOnClickListener {
|
editView.setOnClickListener {
|
||||||
// Navigate to edit
|
//creating a popup menu
|
||||||
fragment.navigateToFragment(
|
val popup = PopupMenu(it.context, it)
|
||||||
FragmentAddItem(),
|
//inflating menu from xml resource
|
||||||
bundle = b,
|
popup.inflate(R.menu.options_menu)
|
||||||
name = "additem"
|
|
||||||
)
|
//adding click listener
|
||||||
}
|
popup.setOnMenuItemClickListener { menu ->
|
||||||
view.setOnLongClickListener {
|
when (menu.itemId) {
|
||||||
AlertDialog.Builder(it.context)
|
R.id.update -> {
|
||||||
.setMessage("Are you sure you want to delete")
|
// Navigate to edit
|
||||||
.setPositiveButton("delete") { _, _ -> longPressCallback.invoke(data.id) }
|
val nav = FragmentMainDirections.mainToAddItem(data.id)
|
||||||
.setNegativeButton("cancel") { dialog, _ ->
|
fragment.navigateParent(nav)
|
||||||
dialog?.dismiss()
|
return@setOnMenuItemClickListener true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.delete -> {
|
||||||
|
AlertDialog.Builder(it.context)
|
||||||
|
.setMessage("Are you sure you want to delete")
|
||||||
|
.setPositiveButton("delete") { _, _ -> viewModel.deleteShift(data.id) }
|
||||||
|
.setNegativeButton("cancel") { dialog, _ ->
|
||||||
|
dialog?.dismiss()
|
||||||
|
}
|
||||||
|
.create().show()
|
||||||
|
return@setOnMenuItemClickListener true
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> return@setOnMenuItemClickListener false
|
||||||
}
|
}
|
||||||
.create().show()
|
}
|
||||||
true
|
//displaying the popup
|
||||||
|
popup.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getItemViewType(position: Int): Int {
|
||||||
|
val typeString = getItem(position).type
|
||||||
|
return when (ShiftType.getEnumByType(typeString)) {
|
||||||
|
ShiftType.HOURLY -> HOURLY_ITEM
|
||||||
|
ShiftType.PIECE -> PIECE_ITEM
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CurrentViewHolder {
|
||||||
|
val layoutId = when (viewType) {
|
||||||
|
HOURLY_ITEM -> R.layout.list_cell_hourly
|
||||||
|
PIECE_ITEM -> R.layout.list_cell_piece
|
||||||
|
else -> {
|
||||||
|
return super.onCreateViewHolder(parent, viewType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val currentView = LayoutInflater
|
||||||
|
.from(parent.context)
|
||||||
|
.inflate(layoutId, parent, false)
|
||||||
|
return CurrentViewHolder(currentView)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val diffCallBack = object : DiffUtil.ItemCallback<ShiftObject>() {
|
val diffCallBack = object : DiffUtil.ItemCallback<ShiftObject>() {
|
||||||
override fun areItemsTheSame(oldItem: ShiftObject, newItem: ShiftObject): Boolean {
|
override fun areItemsTheSame(oldItem: ShiftObject, newItem: ShiftObject): Boolean {
|
||||||
|
|||||||
@@ -4,4 +4,5 @@ const val LEGACY = "LEGACY_"
|
|||||||
const val DATE_FORMAT = "yyyy-MM-dd"
|
const val DATE_FORMAT = "yyyy-MM-dd"
|
||||||
const val TIME_FORMAT = "hh:mm"
|
const val TIME_FORMAT = "hh:mm"
|
||||||
const val ID = "ID"
|
const val ID = "ID"
|
||||||
|
const val SHIFT_ID = "shiftId"
|
||||||
const val CURRENCY = "£"
|
const val CURRENCY = "£"
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.appttude.h_mal.farmr.utils
|
package com.appttude.h_mal.farmr.utils
|
||||||
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import java.math.RoundingMode
|
||||||
import java.text.NumberFormat
|
import java.text.NumberFormat
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
@@ -26,7 +27,7 @@ fun Float.formatAsCurrencyString(): String? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun Float.formatToTwoDpString(): String {
|
fun Float.formatToTwoDpString(): String {
|
||||||
return toBigDecimal().setScale(2).toString()
|
return toBigDecimal().setScale(2, RoundingMode.HALF_DOWN).toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun String.dateStringIsValid(): Boolean {
|
fun String.dateStringIsValid(): Boolean {
|
||||||
@@ -47,6 +48,13 @@ fun String.convertDateString(format: String = DATE_FORMAT): Date? {
|
|||||||
return formatter.parse(this)
|
return formatter.parse(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun String.convertToCalendar(format: String = DATE_FORMAT): Calendar? {
|
||||||
|
val date = convertDateString(format)
|
||||||
|
val calendar = Calendar.getInstance()
|
||||||
|
calendar.time = date ?: return null
|
||||||
|
return calendar
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* turns "HH:mm" into an hour and minutes pair
|
* turns "HH:mm" into an hour and minutes pair
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ fun <CLASS : Any> Any.getGenericClassAt(position: Int): KClass<CLASS> =
|
|||||||
* var s: String?
|
* var s: String?
|
||||||
* i.validate{!i.isNullOrEmpty()} { print("string is empty") }
|
* i.validate{!i.isNullOrEmpty()} { print("string is empty") }
|
||||||
*/
|
*/
|
||||||
inline fun<T: Any?> T.validateField(validate: (T) -> Boolean, onError: () -> Unit) {
|
inline fun <T : Any?> T.validateField(validate: (T) -> Boolean, onError: () -> Unit) {
|
||||||
if (!validate.invoke(this)) {
|
if (!validate.invoke(this)) {
|
||||||
onError.invoke()
|
onError.invoke()
|
||||||
}
|
}
|
||||||
@@ -30,9 +30,25 @@ inline fun<T: Any?> T.validateField(validate: (T) -> Boolean, onError: () -> Uni
|
|||||||
* Returns a list of all elements sorted according to the specified comparator. In order of ascending or descending
|
* Returns a list of all elements sorted according to the specified comparator. In order of ascending or descending
|
||||||
* The sort is stable. It means that equal elements preserve their order relative to each other after sorting.
|
* The sort is stable. It means that equal elements preserve their order relative to each other after sorting.
|
||||||
*/
|
*/
|
||||||
inline fun <T, R : Comparable<R>> Iterable<T>.sortedByOrder(order: Order = Order.ASCENDING, crossinline selector: (T) -> R?): List<T> {
|
inline fun <T, R : Comparable<R>> Iterable<T>.sortedByOrder(
|
||||||
|
order: Order = Order.ASCENDING,
|
||||||
|
crossinline selector: (T) -> R?
|
||||||
|
): List<T> {
|
||||||
return when (order) {
|
return when (order) {
|
||||||
Order.ASCENDING -> sortedWith(compareBy(selector))
|
Order.ASCENDING -> sortedWith(compareBy(selector))
|
||||||
Order.DESCENDING -> sortedWith(compareByDescending(selector))
|
Order.DESCENDING -> sortedWith(compareByDescending(selector))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to retrieve a variable that may throw an exception
|
||||||
|
*
|
||||||
|
* @Returns variable if successful else null
|
||||||
|
*/
|
||||||
|
inline fun <T : Any?> tryGet(validate: () -> T?): T? {
|
||||||
|
return try {
|
||||||
|
validate.invoke()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.appttude.h_mal.farmr.utils
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.navigation.NavDirections
|
||||||
|
import androidx.navigation.Navigation
|
||||||
|
import com.appttude.h_mal.farmr.R
|
||||||
|
import com.appttude.h_mal.farmr.base.ChildFragment
|
||||||
|
|
||||||
|
fun Fragment.navigateToFragment(newFragment: Fragment) {
|
||||||
|
childFragmentManager.beginTransaction()
|
||||||
|
.add(R.id.container, newFragment)
|
||||||
|
.commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun View.navigateTo(navigationId: Int) {
|
||||||
|
Navigation.findNavController(this).navigate(navigationId)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun View.navigateTo(navDirections: NavDirections) {
|
||||||
|
Navigation.findNavController(this).navigate(navDirections)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Fragment.navigateTo(navigationId: Int) {
|
||||||
|
Navigation.findNavController(requireView()).navigate(navigationId)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Fragment.navigateTo(navDirections: NavDirections) {
|
||||||
|
Navigation.findNavController(requireView()).navigate(navDirections)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Fragment.goBack() = Navigation.findNavController(requireView()).popBackStack()
|
||||||
@@ -10,13 +10,7 @@ class InfoViewModel(
|
|||||||
repository: Repository
|
repository: Repository
|
||||||
) : ShiftViewModel(repository) {
|
) : ShiftViewModel(repository) {
|
||||||
|
|
||||||
fun retrieveData(bundle: Bundle?) {
|
fun retrieveData(id: Long) {
|
||||||
val id = bundle?.getLong(ID)
|
|
||||||
if (id == null) {
|
|
||||||
onError("Failed to retrieve shift")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val shift = getCurrentShift(id)
|
val shift = getCurrentShift(id)
|
||||||
if (shift == null) {
|
if (shift == null) {
|
||||||
onError("Failed to retrieve shift")
|
onError("Failed to retrieve shift")
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
package com.appttude.h_mal.farmr.viewmodel
|
package com.appttude.h_mal.farmr.viewmodel
|
||||||
|
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
|
import com.applandeo.materialcalendarview.EventDay
|
||||||
|
import com.appttude.h_mal.farmr.R
|
||||||
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_BREAK
|
||||||
@@ -21,6 +25,7 @@ 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.model.Success
|
||||||
import com.appttude.h_mal.farmr.utils.convertDateString
|
import com.appttude.h_mal.farmr.utils.convertDateString
|
||||||
|
import com.appttude.h_mal.farmr.utils.convertToCalendar
|
||||||
import com.appttude.h_mal.farmr.utils.formatAsCurrencyString
|
import com.appttude.h_mal.farmr.utils.formatAsCurrencyString
|
||||||
import com.appttude.h_mal.farmr.utils.sortedByOrder
|
import com.appttude.h_mal.farmr.utils.sortedByOrder
|
||||||
import jxl.Workbook
|
import jxl.Workbook
|
||||||
@@ -30,6 +35,7 @@ import jxl.write.WritableWorkbook
|
|||||||
import jxl.write.WriteException
|
import jxl.write.WriteException
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import java.util.Calendar
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
|
|
||||||
@@ -42,8 +48,17 @@ class MainViewModel(
|
|||||||
private var mSort: Sortable = Sortable.ID
|
private var mSort: Sortable = Sortable.ID
|
||||||
private var mOrder: Order = Order.ASCENDING
|
private var mOrder: Order = Order.ASCENDING
|
||||||
|
|
||||||
|
private var selectedItemId: Int? = null
|
||||||
|
|
||||||
private val observer = Observer<List<ShiftEntity>> {
|
private val observer = Observer<List<ShiftEntity>> {
|
||||||
it?.let { updateFiltrationAndPostResults(it) }
|
it?.let { updateFiltrationAndPostResults(it) }
|
||||||
|
private var selectedItemId: Int? = null
|
||||||
|
|
||||||
|
private val observer = Observer<List<ShiftObject>> {
|
||||||
|
it?.let {
|
||||||
|
val result = it.applyFilters().sortList(mSort, mOrder)
|
||||||
|
onSuccess(result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -103,7 +118,7 @@ class MainViewModel(
|
|||||||
if (second == null) return compareDate.after(first)
|
if (second == null) return compareDate.after(first)
|
||||||
if (first == null) return compareDate.before(second)
|
if (first == null) return compareDate.before(second)
|
||||||
|
|
||||||
return compareDate.after(first) && compareDate.before(second)
|
return compareDate.compareTo(first) * second.compareTo(compareDate) >= 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -211,9 +226,8 @@ class MainViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun clearFilters() {
|
fun clearFilters() {
|
||||||
super.setFiltrationDetails(null, null, null, null)
|
val result = super.setFiltrationDetails(null, null, null, null)
|
||||||
onSuccess(Success("Filters have been cleared"))
|
if (result) refreshLiveData()
|
||||||
refreshLiveData()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -298,4 +312,25 @@ class MainViewModel(
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun retrieveEvents(): List<EventDay>? {
|
||||||
|
val shiftList = shiftLiveData.value ?: return null
|
||||||
|
return shiftList.applyFilters().mapNotNull {
|
||||||
|
it.date.convertToCalendar()
|
||||||
|
?.let { d -> EventDay(d, R.drawable.baseline_list_alt_24, Color.parseColor("#228B22")) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getShiftsOnTheDay(calendar: Calendar): List<ShiftObject>? {
|
||||||
|
val shiftList = shiftLiveData.value ?: return null
|
||||||
|
return shiftList.filter { it.date.convertToCalendar()?.compareTo(calendar) == 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveBottomBarState(selectedItemId: Int) {
|
||||||
|
this.selectedItemId = selectedItemId
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBottomBarState(): Int? {
|
||||||
|
return selectedItemId
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -18,25 +18,13 @@ open class ShiftViewModel(
|
|||||||
*/
|
*/
|
||||||
fun getCurrentShift(id: Long) = repository.readSingleShiftFromDatabase(id)
|
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(
|
open fun setFiltrationDetails(
|
||||||
description: String?,
|
description: String?,
|
||||||
dateFrom: String?,
|
dateFrom: String?,
|
||||||
dateTo: String?,
|
dateTo: String?,
|
||||||
type: String?
|
type: String?
|
||||||
) {
|
): Boolean {
|
||||||
repository.setFilteringDetailsInPrefs(description, dateFrom, dateTo, type)
|
return repository.setFilteringDetailsInPrefs(description, dateFrom, dateTo, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun getFiltrationDetails(): FilterStore {
|
open fun getFiltrationDetails(): FilterStore {
|
||||||
|
|||||||
@@ -289,6 +289,7 @@ class SubmissionViewModel(
|
|||||||
description = description,
|
description = description,
|
||||||
date = date,
|
date = date,
|
||||||
units = units!!,
|
units = units!!,
|
||||||
|
|
||||||
rateOfPay = rateOfPay,
|
rateOfPay = rateOfPay,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
5
app/src/main/res/drawable/baseline_calendar_month_24.xml
Normal file
5
app/src/main/res/drawable/baseline_calendar_month_24.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="#000000"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M19,4h-1V2h-2v2H8V2H6v2H5C3.89,4 3.01,4.9 3.01,6L3,20c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V6C21,4.9 20.1,4 19,4zM19,20H5V10h14V20zM9,14H7v-2h2V14zM13,14h-2v-2h2V14zM17,14h-2v-2h2V14zM9,18H7v-2h2V18zM13,18h-2v-2h2V18zM17,18h-2v-2h2V18z"/>
|
||||||
|
</vector>
|
||||||
5
app/src/main/res/drawable/baseline_list_alt_24.xml
Normal file
5
app/src/main/res/drawable/baseline_list_alt_24.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:autoMirrored="true" android:height="24dp"
|
||||||
|
android:tint="#000000" android:viewportHeight="24"
|
||||||
|
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M19,5v14L5,19L5,5h14m1.1,-2L3.9,3c-0.5,0 -0.9,0.4 -0.9,0.9v16.2c0,0.4 0.4,0.9 0.9,0.9h16.2c0.4,0 0.9,-0.5 0.9,-0.9L21,3.9c0,-0.5 -0.5,-0.9 -0.9,-0.9zM11,7h6v2h-6L11,7zM11,11h6v2h-6v-2zM11,15h6v2h-6zM7,7h2v2L7,9zM7,11h2v2L7,13zM7,15h2v2L7,17z"/>
|
||||||
|
</vector>
|
||||||
5
app/src/main/res/drawable/baseline_more_vert_24.xml
Normal file
5
app/src/main/res/drawable/baseline_more_vert_24.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="#000000"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
|
||||||
|
</vector>
|
||||||
135
app/src/main/res/layout-v26/list_cell_hourly.xml
Normal file
135
app/src/main/res/layout-v26/list_cell_hourly.xml
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/linearLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:divider="#656565"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingTop="24dp"
|
||||||
|
android:paddingBottom="24dp"
|
||||||
|
android:showDividers="end">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/time_holder"
|
||||||
|
android:layout_width="@dimen/unit_holder_width"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:gravity="end"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/hours"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
tools:text="00"
|
||||||
|
android:textColor="#143d66"
|
||||||
|
android:textSize="@dimen/unit_text_size" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/h"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/hours_symbol"
|
||||||
|
android:textColor="#143d66"
|
||||||
|
android:textSize="@dimen/units_symbol_size" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/minutes"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
tools:text="00"
|
||||||
|
android:textColor="#143d66"
|
||||||
|
android:textSize="@dimen/unit_text_size" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/m"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/minutes_symbol"
|
||||||
|
android:textColor="#143d66"
|
||||||
|
android:textSize="@dimen/units_symbol_size" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/totalpay_holder"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintRight_toRightOf="@id/time_holder"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/time_holder">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/currency"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/pound_sign"
|
||||||
|
android:textColor="#728fcc"
|
||||||
|
android:textSize="@dimen/units_symbol_size" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/total_pay"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
tools:text="000.00"
|
||||||
|
android:textColor="#728fcc"
|
||||||
|
android:textSize="@dimen/total_pay_size" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/line"
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginLeft="6dp"
|
||||||
|
android:layout_marginRight="6dp"
|
||||||
|
android:background="@android:color/darker_gray"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/totalpay_holder"
|
||||||
|
app:layout_constraintLeft_toRightOf="@id/time_holder"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/time_holder" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/location"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginLeft="6dp"
|
||||||
|
android:layout_marginRight="6dp"
|
||||||
|
android:gravity="bottom|start"
|
||||||
|
android:textColor="#000000"
|
||||||
|
android:textSize="@dimen/location_size"
|
||||||
|
android:autoSizeMinTextSize="@dimen/location_autosize_min"
|
||||||
|
android:autoSizeTextType="uniform"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/time_holder"
|
||||||
|
app:layout_constraintLeft_toRightOf="@id/line"
|
||||||
|
app:layout_constraintRight_toLeftOf="@id/imageView"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_bias="1.0"
|
||||||
|
android:maxLines="2"
|
||||||
|
tools:text="Location Name is quite long and with a second line and more" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/date"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:maxLines="3"
|
||||||
|
tools:text="01-05-2010"
|
||||||
|
android:textSize="@dimen/date_size"
|
||||||
|
android:gravity="center"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/location"
|
||||||
|
app:layout_constraintLeft_toLeftOf="@id/location"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/totalpay_holder"/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/imageView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:srcCompat="@drawable/baseline_more_vert_24"
|
||||||
|
android:layout_marginEnd="12dp" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
118
app/src/main/res/layout-v26/list_cell_piece.xml
Normal file
118
app/src/main/res/layout-v26/list_cell_piece.xml
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/linearLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:divider="#656565"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingTop="24dp"
|
||||||
|
android:paddingBottom="24dp"
|
||||||
|
android:showDividers="end">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/time_holder"
|
||||||
|
android:layout_width="@dimen/unit_holder_width"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:gravity="end"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/pieces"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
tools:text="10.0"
|
||||||
|
android:textColor="#143d66"
|
||||||
|
android:textSize="@dimen/unit_text_size" />
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/h"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/piece_symbol"
|
||||||
|
android:textColor="#143d66"
|
||||||
|
android:textSize="@dimen/units_symbol_size" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/totalpay_holder"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintRight_toRightOf="@id/time_holder"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/time_holder">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/currency"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/pound_sign"
|
||||||
|
android:textColor="#728fcc"
|
||||||
|
android:textSize="@dimen/units_symbol_size" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/total_pay"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
tools:text="000.00"
|
||||||
|
android:textColor="#728fcc"
|
||||||
|
android:textSize="@dimen/total_pay_size" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/line"
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginLeft="6dp"
|
||||||
|
android:layout_marginRight="6dp"
|
||||||
|
android:background="@android:color/darker_gray"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/totalpay_holder"
|
||||||
|
app:layout_constraintLeft_toRightOf="@id/time_holder"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/time_holder" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/location"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginLeft="6dp"
|
||||||
|
android:layout_marginRight="6dp"
|
||||||
|
android:gravity="bottom|start"
|
||||||
|
android:textColor="#000000"
|
||||||
|
android:textSize="@dimen/location_size"
|
||||||
|
android:autoSizeMinTextSize="@dimen/location_autosize_min"
|
||||||
|
android:autoSizeTextType="uniform"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/time_holder"
|
||||||
|
app:layout_constraintLeft_toRightOf="@id/line"
|
||||||
|
app:layout_constraintRight_toLeftOf="@id/imageView"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_bias="1.0"
|
||||||
|
android:maxLines="2"
|
||||||
|
tools:text="Location Name is quite long and with a second line" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/date"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:maxLines="3"
|
||||||
|
tools:text="01-05-2010"
|
||||||
|
android:textSize="@dimen/date_size"
|
||||||
|
android:gravity="center"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/location"
|
||||||
|
app:layout_constraintLeft_toLeftOf="@id/location"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/totalpay_holder"/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/imageView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:srcCompat="@drawable/baseline_more_vert_24"
|
||||||
|
android:layout_marginEnd="12dp" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
38
app/src/main/res/layout/fragment_calendar.xml
Normal file
38
app/src/main/res/layout/fragment_calendar.xml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||||
|
tools:context=".ui.CalendarFragment">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||||
|
android:paddingTop="@dimen/activity_vertical_margin"
|
||||||
|
android:paddingRight="@dimen/activity_horizontal_margin">
|
||||||
|
|
||||||
|
<com.applandeo.materialcalendarview.CalendarView
|
||||||
|
android:id="@+id/calendarView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:headerColor="@color/colorPrimary"
|
||||||
|
app:highlightedDaysLabelsColor="@color/colorPrimary"
|
||||||
|
app:selectionColor="@color/colorAccent"
|
||||||
|
app:type="classic" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/shifts_available_recycler"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/activity_horizontal_margin"
|
||||||
|
android:nestedScrollingEnabled="false"
|
||||||
|
tools:itemCount="5"
|
||||||
|
tools:listitem="@layout/list_cell_hourly" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
24
app/src/main/res/layout/fragment_list.xml
Normal file
24
app/src/main/res/layout/fragment_list.xml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<RelativeLayout 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"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
tools:context="com.appttude.h_mal.farmr.ui.FragmentList">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/list_item_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
tools:listitem="@layout/list_cell_hourly">
|
||||||
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:visibility="visible"
|
||||||
|
layout="@layout/empty_list_view"
|
||||||
|
android:id="@+id/empty_view"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"/>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
@@ -1,34 +1,39 @@
|
|||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
tools:context="com.appttude.h_mal.farmr.ui.FragmentMain">
|
tools:context="com.appttude.h_mal.farmr.ui.FragmentMain">
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.fragment.app.FragmentContainerView
|
||||||
android:id="@+id/list_item_view"
|
android:id="@+id/sub_container"
|
||||||
|
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
app:layout_constraintBottom_toTopOf="@id/bottom_bar"
|
||||||
tools:listitem="@layout/list_item_1">
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
</androidx.recyclerview.widget.RecyclerView>
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:layout="@layout/fragment_calendar" />
|
||||||
|
|
||||||
|
<com.google.android.material.bottomnavigation.BottomNavigationView
|
||||||
|
android:id="@+id/bottom_bar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:menu="@menu/bottom_navigation_menu" />
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
android:id="@+id/fab1"
|
android:id="@+id/fab1"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentRight="true"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
android:layout_alignParentBottom="true"
|
app:layout_constraintBottom_toTopOf="@id/bottom_bar"
|
||||||
android:layout_margin="@dimen/fab_margin"
|
android:layout_margin="@dimen/fab_margin"
|
||||||
|
android:contentDescription="@string/fab"
|
||||||
android:src="@drawable/add"
|
android:src="@drawable/add"
|
||||||
app:backgroundTint="@color/colorPrimary" />
|
app:backgroundTint="@color/colorPrimary" />
|
||||||
|
|
||||||
<include
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
android:layout_centerInParent="true"
|
|
||||||
android:visibility="visible"
|
|
||||||
layout="@layout/empty_list_view"
|
|
||||||
android:id="@+id/empty_view"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|||||||
132
app/src/main/res/layout/list_cell_hourly.xml
Normal file
132
app/src/main/res/layout/list_cell_hourly.xml
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/linearLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:divider="#656565"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingTop="24dp"
|
||||||
|
android:paddingBottom="24dp"
|
||||||
|
android:showDividers="end">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/time_holder"
|
||||||
|
android:layout_width="@dimen/unit_holder_width"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/hours"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
tools:text="00"
|
||||||
|
android:textColor="#143d66"
|
||||||
|
android:textSize="@dimen/unit_text_size" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/h"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/hours_symbol"
|
||||||
|
android:textColor="#143d66"
|
||||||
|
android:textSize="@dimen/units_symbol_size" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/minutes"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
tools:text="00"
|
||||||
|
android:textColor="#143d66"
|
||||||
|
android:textSize="@dimen/unit_text_size" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/m"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/minutes_symbol"
|
||||||
|
android:textColor="#143d66"
|
||||||
|
android:textSize="@dimen/units_symbol_size" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/totalpay_holder"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintRight_toRightOf="@id/time_holder"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/time_holder">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/currency"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/pound_sign"
|
||||||
|
android:textColor="#728fcc"
|
||||||
|
android:textSize="@dimen/units_symbol_size" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/total_pay"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
tools:text="000.00"
|
||||||
|
android:textColor="#728fcc"
|
||||||
|
android:textSize="@dimen/total_pay_size" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/line"
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginLeft="6dp"
|
||||||
|
android:layout_marginRight="6dp"
|
||||||
|
android:background="@android:color/darker_gray"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/totalpay_holder"
|
||||||
|
app:layout_constraintLeft_toRightOf="@id/time_holder"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/time_holder" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/location"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginLeft="6dp"
|
||||||
|
android:layout_marginRight="6dp"
|
||||||
|
android:gravity="bottom|start"
|
||||||
|
android:textColor="#000000"
|
||||||
|
android:textSize="@dimen/location_size"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/time_holder"
|
||||||
|
app:layout_constraintLeft_toRightOf="@id/line"
|
||||||
|
app:layout_constraintRight_toLeftOf="@id/imageView"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_bias="1.0"
|
||||||
|
android:maxLines="1"
|
||||||
|
tools:text="Location Name" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/date"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:maxLines="3"
|
||||||
|
tools:text="01-05-2010"
|
||||||
|
android:textSize="@dimen/date_size"
|
||||||
|
android:gravity="center"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/location"
|
||||||
|
app:layout_constraintLeft_toLeftOf="@id/location"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/totalpay_holder"/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/imageView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:srcCompat="@drawable/baseline_more_vert_24"
|
||||||
|
android:layout_marginEnd="12dp" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
117
app/src/main/res/layout/list_cell_piece.xml
Normal file
117
app/src/main/res/layout/list_cell_piece.xml
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/linearLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:divider="#656565"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingTop="24dp"
|
||||||
|
android:paddingBottom="24dp"
|
||||||
|
android:showDividers="end">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/time_holder"
|
||||||
|
android:layout_width="@dimen/unit_holder_width"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:gravity="end"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/pieces"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
tools:text="10.0"
|
||||||
|
android:textColor="#143d66"
|
||||||
|
android:textSize="@dimen/unit_text_size" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/h"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/piece_symbol"
|
||||||
|
android:textColor="#143d66"
|
||||||
|
android:textSize="@dimen/units_symbol_size" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/totalpay_holder"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintRight_toRightOf="@id/time_holder"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/time_holder">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/currency"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/pound_sign"
|
||||||
|
android:textColor="#728fcc"
|
||||||
|
android:textSize="@dimen/units_symbol_size" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/total_pay"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
tools:text="000.00"
|
||||||
|
android:textColor="#728fcc"
|
||||||
|
android:textSize="@dimen/total_pay_size" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/line"
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginLeft="6dp"
|
||||||
|
android:layout_marginRight="6dp"
|
||||||
|
android:background="@android:color/darker_gray"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/totalpay_holder"
|
||||||
|
app:layout_constraintLeft_toRightOf="@id/time_holder"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/time_holder" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/location"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginLeft="6dp"
|
||||||
|
android:layout_marginRight="6dp"
|
||||||
|
android:gravity="bottom|start"
|
||||||
|
android:textColor="#000000"
|
||||||
|
android:textSize="@dimen/location_size"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/time_holder"
|
||||||
|
app:layout_constraintLeft_toRightOf="@id/line"
|
||||||
|
app:layout_constraintRight_toLeftOf="@id/imageView"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_bias="1.0"
|
||||||
|
android:maxLines="1"
|
||||||
|
tools:text="Location Name" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/date"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:maxLines="3"
|
||||||
|
tools:text="01-05-2010"
|
||||||
|
android:textSize="@dimen/date_size"
|
||||||
|
android:gravity="center"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/location"
|
||||||
|
app:layout_constraintLeft_toLeftOf="@id/location"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/totalpay_holder"/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/imageView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:srcCompat="@drawable/baseline_more_vert_24"
|
||||||
|
android:layout_marginEnd="12dp" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/linearLayout"
|
android:id="@+id/linearLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@@ -8,10 +9,11 @@
|
|||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingBottom="24dp"
|
android:paddingBottom="24dp"
|
||||||
android:paddingTop="24dp"
|
android:paddingTop="24dp"
|
||||||
android:showDividers="end">
|
android:showDividers="end"
|
||||||
|
tools:ignore="HardcodedText">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="87dp"
|
android:layout_width="@dimen/unit_holder_width"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|
||||||
android:layout_marginStart="12dp"
|
android:layout_marginStart="12dp"
|
||||||
@@ -30,7 +32,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="00"
|
android:text="00"
|
||||||
android:textColor="#143d66"
|
android:textColor="#143d66"
|
||||||
android:textSize="30sp" />
|
android:textSize="@dimen/unit_text_size" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/h"
|
android:id="@+id/h"
|
||||||
@@ -38,7 +40,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="h"
|
android:text="h"
|
||||||
android:textColor="#143d66"
|
android:textColor="#143d66"
|
||||||
android:textSize="12sp" />
|
android:textSize="@dimen/units_symbol_size" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/minutes"
|
android:id="@+id/minutes"
|
||||||
@@ -47,7 +49,7 @@
|
|||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:text="00"
|
android:text="00"
|
||||||
android:textColor="#143d66"
|
android:textColor="#143d66"
|
||||||
android:textSize="30sp" />
|
android:textSize="@dimen/unit_text_size"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/m"
|
android:id="@+id/m"
|
||||||
@@ -56,7 +58,7 @@
|
|||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:text="m"
|
android:text="m"
|
||||||
android:textColor="#143d66"
|
android:textColor="#143d66"
|
||||||
android:textSize="12sp" />
|
android:textSize="@dimen/units_symbol_size" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@@ -70,9 +72,9 @@
|
|||||||
android:id="@+id/currency"
|
android:id="@+id/currency"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="£"
|
android:text="@string/pound_sign"
|
||||||
android:textColor="#728fcc"
|
android:textColor="#728fcc"
|
||||||
android:textSize="12sp" />
|
android:textSize="@dimen/units_symbol_size" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/total_pay"
|
android:id="@+id/total_pay"
|
||||||
@@ -80,7 +82,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="000.00"
|
android:text="000.00"
|
||||||
android:textColor="#728fcc"
|
android:textColor="#728fcc"
|
||||||
android:textSize="20sp" />
|
android:textSize="@dimen/total_pay_size" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
@@ -106,7 +108,7 @@
|
|||||||
android:layout_below="@+id/date"
|
android:layout_below="@+id/date"
|
||||||
android:maxLines="3"
|
android:maxLines="3"
|
||||||
android:text="Location Name"
|
android:text="Location Name"
|
||||||
android:textSize="20sp" />
|
android:textSize="@dimen/location_size" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/date"
|
android:id="@+id/date"
|
||||||
@@ -119,7 +121,7 @@
|
|||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:text="01-05-2010"
|
android:text="01-05-2010"
|
||||||
android:textColor="#000000"
|
android:textColor="#000000"
|
||||||
android:textSize="16sp" />
|
android:textSize="@dimen/date_size" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/imageView"
|
android:id="@+id/imageView"
|
||||||
|
|||||||
@@ -32,14 +32,17 @@
|
|||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
<FrameLayout
|
<androidx.fragment.app.FragmentContainerView
|
||||||
android:layout_below="@id/appbar"
|
android:layout_below="@id/appbar"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
|
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||||
app:layout_constraintTop_toBottomOf="@id/appbar"
|
app:layout_constraintTop_toBottomOf="@id/appbar"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
android:id="@+id/container">
|
app:defaultNavHost="true"
|
||||||
</FrameLayout>
|
android:id="@+id/container"
|
||||||
|
tools:layout="@layout/fragment_main">
|
||||||
|
</androidx.fragment.app.FragmentContainerView>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
14
app/src/main/res/menu/bottom_navigation_menu.xml
Normal file
14
app/src/main/res/menu/bottom_navigation_menu.xml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_list"
|
||||||
|
app:showAsAction="always|withText"
|
||||||
|
android:icon="@drawable/baseline_list_alt_24"
|
||||||
|
android:title="@string/text_label_1"/>
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_calendar"
|
||||||
|
app:showAsAction="always|withText"
|
||||||
|
android:icon="@drawable/baseline_calendar_month_24"
|
||||||
|
android:title="@string/text_label_2"/>
|
||||||
|
</menu>
|
||||||
14
app/src/main/res/menu/options_menu.xml
Normal file
14
app/src/main/res/menu/options_menu.xml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
<item
|
||||||
|
android:id="@+id/update"
|
||||||
|
android:orderInCategory="100"
|
||||||
|
android:title="@string/update_shift"
|
||||||
|
app:showAsAction="never" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/delete"
|
||||||
|
android:orderInCategory="100"
|
||||||
|
android:title="@string/delete_shift"
|
||||||
|
app:showAsAction="never" />
|
||||||
|
</menu>
|
||||||
17
app/src/main/res/navigation/home_navigation.xml
Normal file
17
app/src/main/res/navigation/home_navigation.xml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/shift_navigation"
|
||||||
|
app:startDestination="@id/nav_list">
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_list"
|
||||||
|
android:name="com.appttude.h_mal.farmr.ui.FragmentList"
|
||||||
|
android:label="@string/text_label_1"
|
||||||
|
tools:layout="@layout/fragment_list" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_calendar"
|
||||||
|
android:name="com.appttude.h_mal.farmr.ui.CalendarFragment"
|
||||||
|
android:label="@string/text_label_2"
|
||||||
|
tools:layout="@layout/fragment_calendar" />
|
||||||
|
</navigation>
|
||||||
65
app/src/main/res/navigation/shift_navigation.xml
Normal file
65
app/src/main/res/navigation/shift_navigation.xml
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/shift_navigation"
|
||||||
|
app:startDestination="@id/fragmentMain">
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/fragmentMain"
|
||||||
|
android:name="com.appttude.h_mal.farmr.ui.FragmentMain"
|
||||||
|
android:label="fragment_main"
|
||||||
|
tools:layout="@layout/fragment_main" >
|
||||||
|
<action
|
||||||
|
android:id="@+id/main_to_addItem"
|
||||||
|
app:destination="@id/fragmentAddItem"
|
||||||
|
app:enterAnim="@anim/nav_default_enter_anim"
|
||||||
|
app:exitAnim="@anim/nav_default_exit_anim"
|
||||||
|
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||||
|
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/main_to_filterData"
|
||||||
|
app:destination="@id/filterDataFragment"
|
||||||
|
app:enterAnim="@anim/nav_default_enter_anim"
|
||||||
|
app:exitAnim="@anim/nav_default_exit_anim"
|
||||||
|
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||||
|
app:popExitAnim="@anim/nav_default_pop_exit_anim"/>
|
||||||
|
<action
|
||||||
|
android:id="@+id/main_to_furtherInfo"
|
||||||
|
app:destination="@id/furtherInfoFragment"
|
||||||
|
app:enterAnim="@anim/nav_default_enter_anim"
|
||||||
|
app:exitAnim="@anim/nav_default_exit_anim"
|
||||||
|
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||||
|
app:popExitAnim="@anim/nav_default_pop_exit_anim"/>
|
||||||
|
</fragment>
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/fragmentAddItem"
|
||||||
|
android:name="com.appttude.h_mal.farmr.ui.FragmentAddItem"
|
||||||
|
android:label="fragment_add_item"
|
||||||
|
tools:layout="@layout/fragment_add_item">
|
||||||
|
<argument
|
||||||
|
android:name="shiftId"
|
||||||
|
app:argType="long" />
|
||||||
|
</fragment>
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/filterDataFragment"
|
||||||
|
android:name="com.appttude.h_mal.farmr.ui.FilterDataFragment"
|
||||||
|
android:label="fragment_filter_data"
|
||||||
|
tools:layout="@layout/fragment_filter_data" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/furtherInfoFragment"
|
||||||
|
android:name="com.appttude.h_mal.farmr.ui.FurtherInfoFragment"
|
||||||
|
android:label="fragment_futher_info"
|
||||||
|
tools:layout="@layout/fragment_futher_info" >
|
||||||
|
<action
|
||||||
|
android:id="@+id/furtherInfo_to_AddItem"
|
||||||
|
app:destination="@id/fragmentAddItem"
|
||||||
|
app:enterAnim="@anim/nav_default_enter_anim"
|
||||||
|
app:exitAnim="@anim/nav_default_exit_anim"
|
||||||
|
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||||
|
app:popExitAnim="@anim/nav_default_pop_exit_anim"/>
|
||||||
|
<argument
|
||||||
|
android:name="shiftId"
|
||||||
|
app:argType="long" />
|
||||||
|
</fragment>
|
||||||
|
</navigation>
|
||||||
@@ -4,6 +4,13 @@
|
|||||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||||
<dimen name="fab_margin">16dp</dimen>
|
<dimen name="fab_margin">16dp</dimen>
|
||||||
<dimen name="appbar_padding_top">8dp</dimen>
|
<dimen name="appbar_padding_top">8dp</dimen>
|
||||||
|
<dimen name="unit_text_size">20sp</dimen>
|
||||||
|
<dimen name="units_symbol_size">12sp</dimen>
|
||||||
|
<dimen name="total_pay_size">16sp</dimen>
|
||||||
|
<dimen name="location_size">16sp</dimen>
|
||||||
|
<dimen name="date_size">14sp</dimen>
|
||||||
|
<dimen name="unit_holder_width">75dp</dimen>
|
||||||
|
<dimen name="location_autosize_min">12sp</dimen>
|
||||||
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -87,14 +87,18 @@
|
|||||||
<string name="export">Export Data</string>
|
<string name="export">Export Data</string>
|
||||||
<string name="sort">Sort</string>
|
<string name="sort">Sort</string>
|
||||||
|
|
||||||
<string name="admob_unit_id">ca-app-pub-3406791512187471/7557456476</string>
|
|
||||||
<string name="banner_home_footer">ca-app-pub-3406791512187471~9541579845</string>
|
|
||||||
|
|
||||||
<string name="help">Help & Support</string>
|
<string name="help">Help & Support</string>
|
||||||
|
|
||||||
<!-- TODO: Remove or change this placeholder text -->
|
|
||||||
<string name="hello_blank_fragment">Hello blank fragment</string>
|
|
||||||
<string name="further_info_title">Shift Details</string>
|
<string name="further_info_title">Shift Details</string>
|
||||||
<string name="insert_break_in_minutes">insert break in minutes</string>
|
<string name="insert_break_in_minutes">insert break in minutes</string>
|
||||||
<string name="break_res">Break</string>
|
<string name="break_res">Break</string>
|
||||||
|
<string name="hours_symbol">h</string>
|
||||||
|
<string name="minutes_symbol">m</string>
|
||||||
|
<string name="piece_symbol">pcs</string>
|
||||||
|
<string name="pound_sign">£</string>
|
||||||
|
<string name="delete_shift">Delete Shift</string>
|
||||||
|
<string name="update_shift">Update Shift</string>
|
||||||
|
<string name="fab">Floating action button</string>
|
||||||
|
<string name="text_label_1">Shifts</string>
|
||||||
|
<string name="text_label_2">Calendar</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -56,12 +56,10 @@ class InfoViewModelTest : ShiftViewModelTest<InfoViewModel>() {
|
|||||||
fun retrieveData_validBundleNoShift_successfulRetrieval() {
|
fun retrieveData_validBundleNoShift_successfulRetrieval() {
|
||||||
// Arrange
|
// Arrange
|
||||||
val id = anyLong()
|
val id = anyLong()
|
||||||
val bundle = mockk<Bundle>()
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
every { repository.readSingleShiftFromDatabase(id) }.returns(null)
|
every { repository.readSingleShiftFromDatabase(id) }.returns(null)
|
||||||
every { bundle.getLong(ID) }.returns(id)
|
viewModel.retrieveData(id)
|
||||||
viewModel.retrieveData(bundle)
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
assertEquals(
|
assertEquals(
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ class MainViewModelTest {
|
|||||||
val retrievedShifts = retrieveCurrentData()
|
val retrievedShifts = retrieveCurrentData()
|
||||||
val description = viewModel.getInformation()
|
val description = viewModel.getInformation()
|
||||||
|
|
||||||
every { repository.setFilteringDetailsInPrefs(null, null, null, null) }.returns(Unit)
|
every { repository.setFilteringDetailsInPrefs(null, null, null, null) }.returns(true)
|
||||||
every { repository.retrieveFilteringDetailsInPrefs() }.returns(getFilter())
|
every { repository.retrieveFilteringDetailsInPrefs() }.returns(getFilter())
|
||||||
viewModel.clearFilters()
|
viewModel.clearFilters()
|
||||||
val descriptionAfterClearedFilter = viewModel.getInformation()
|
val descriptionAfterClearedFilter = viewModel.getInformation()
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ buildscript {
|
|||||||
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
|
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
|
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$NAVIGATION_VERSION"
|
||||||
classpath "com.android.tools.build:gradle:$GRADLE_PLUGIN_VERSION"
|
classpath "com.android.tools.build:gradle:$GRADLE_PLUGIN_VERSION"
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$KOTLIN_VERSION"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$KOTLIN_VERSION"
|
||||||
classpath "com.autonomousapps:dependency-analysis-gradle-plugin:$GRADLE_ANALYZE_VERSION"
|
classpath "com.autonomousapps:dependency-analysis-gradle-plugin:$GRADLE_ANALYZE_VERSION"
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ platform :android do
|
|||||||
|
|
||||||
desc "Deploy a new version to the Google Play"
|
desc "Deploy a new version to the Google Play"
|
||||||
lane :deploy do
|
lane :deploy do
|
||||||
gradle(task: "clean assembleRelease")
|
gradle(task: "clean bundle", build_type: "Release")
|
||||||
upload_to_play_store
|
upload_to_play_store
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ MATERIAL_VERSION = 1.0.0
|
|||||||
CONSTR_LAYOUT_VERSION = 1.1.3
|
CONSTR_LAYOUT_VERSION = 1.1.3
|
||||||
LIFECYCLE_VERSION = 2.5.1
|
LIFECYCLE_VERSION = 2.5.1
|
||||||
VIEWMODEL_VERSION = 2.4.1
|
VIEWMODEL_VERSION = 2.4.1
|
||||||
|
NAVIGATION_VERSION = 2.3.2
|
||||||
PREFERENCES_VERSION = 1.2.1
|
PREFERENCES_VERSION = 1.2.1
|
||||||
MOKITO_INLINE_VERSION = 2.13.0
|
MOKITO_INLINE_VERSION = 2.13.0
|
||||||
CORE_TEST_VERSION = 2.1.0
|
CORE_TEST_VERSION = 2.1.0
|
||||||
@@ -26,8 +27,8 @@ KOTLIN_VERSION = 1.7.10
|
|||||||
GRADLE_ANALYZE_VERSION = 1.20.0
|
GRADLE_ANALYZE_VERSION = 1.20.0
|
||||||
|
|
||||||
# Android configuration
|
# Android configuration
|
||||||
COMPILE_SDK_VERSION = android-31
|
COMPILE_SDK_VERSION = android-33
|
||||||
TARGET_SDK_VERSION = 31
|
TARGET_SDK_VERSION = 33
|
||||||
MIN_SDK_VERSION = 21
|
MIN_SDK_VERSION = 21
|
||||||
|
|
||||||
# Gradle parameters
|
# Gradle parameters
|
||||||
|
|||||||
Reference in New Issue
Block a user