Skip to content

Commit

Permalink
Move battery warning functionality to ClockPageViewModelState (#25)
Browse files Browse the repository at this point in the history
* Finish moving TaskTextFieldIcon functionality to ViewModelState, kept data saving logic in ViewModel. Wrote unit and instrumented tests.
  • Loading branch information
NicksPatties authored Aug 12, 2022
1 parent 61679ad commit d99bb7a
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,44 @@ class ClockPageTest {
.assertTextEquals(testString)
}

@Test
fun taskNameIcon_countDownTimerAppears() {
composeTestRule.setContent {
TimeClockTheme {
ClockPage(
viewModelState = ClockPageViewModelState()
)
}
}
composeTestRule.onNodeWithTag("TaskTextField_IconButton").performClick()
composeTestRule.onNodeWithTag("TimerTextField_Hours")
.assertIsDisplayed()
.assertIsEnabled()
composeTestRule.onNodeWithTag("TimerTextField_Minutes")
.assertIsDisplayed()
.assertIsEnabled()
composeTestRule.onNodeWithTag("TimerTextField_Seconds")
.assertIsDisplayed()
.assertIsEnabled()
}

@Test
fun taskNameIcon_countDownTimerDisappearsIfAlreadyEnabled() {
composeTestRule.setContent {
TimeClockTheme {
ClockPage(
viewModelState = ClockPageViewModelState(
countDownTimerEnabled = true
)
)
}
}
composeTestRule.onNodeWithTag("TaskTextField_IconButton").performClick()
composeTestRule.onNodeWithTag("TimerTextField_Hours").assertDoesNotExist()
composeTestRule.onNodeWithTag("TimerTextField_Minutes").assertDoesNotExist()
composeTestRule.onNodeWithTag("TimerTextField_Seconds").assertDoesNotExist()
}

@Test
fun taskNameDropdown_dropdownAppearsAndTaskFillsInWhenLabelIsClicked() {
composeTestRule.setContent {
Expand Down Expand Up @@ -123,4 +161,4 @@ class ClockPageTest {
composeTestRule.onNodeWithTag("TimerTextField_Minutes").performTextInput("1")
composeTestRule.onNodeWithTag("StartTimerButton").assertIsEnabled()
}
}
}
18 changes: 14 additions & 4 deletions app/src/main/java/com/nickspatties/timeclock/ui/pages/ClockPage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ fun ClockPage(

if (viewModelState.batteryWarningDialogVisible) {
BatteryWarningDialog(
confirmFunction = viewModelState.batteryWarningConfirmFunction,
dismissFunction = viewModelState.batteryWarningDismissFunction
confirmFunction = viewModelState::confirmBatteryWarningDialog,
dismissFunction = viewModelState::dismissBatteryWarningDialog
)
}

Scaffold() {
Scaffold {
Column(
modifier = Modifier
.padding(it)
Expand Down Expand Up @@ -63,7 +63,7 @@ fun ClockPage(
},
keyboardController = keyboardController,
countdownTimerEnabled = viewModelState.countDownTimerEnabled,
onIconClick = viewModelState.onTaskNameIconClick
onIconClick = viewModelState::onTaskTextFieldIconClick
)

DropdownMenu(
Expand Down Expand Up @@ -138,4 +138,14 @@ fun ClockPage_Initial() {
ClockPage(
viewModelState = ClockPageViewModelState()
)
}

@Composable
@Preview
fun ClockPage_batteryDialogVisible() {
ClockPage(
viewModelState = ClockPageViewModelState(
batteryWarningDialogVisible = true
)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ class ClockPageViewModel (
// only occurs when the class is created, not when moving from view to view
init {
// state function declarations
state.batteryWarningConfirmFunction = this::goToBatterySettings
state.batteryWarningDismissFunction = this::hideBatteryWarningModal
state.onTaskNameIconClick = this::switchCountDownTimer
state.checkBatteryOptimizationSettings = this::checkBatteryOptimizationSettings
state.startBatteryManagementActivity = this::goToBatterySettings
state.saveCountDownTimerEnabledValue = this::saveCountDownTimerEnabled
state.onTimerAnimationFinish = this::resetCurrSeconds
state.onClockStart = this::startClock
state.onClockStop = this::stopClock
Expand Down Expand Up @@ -139,27 +139,20 @@ class ClockPageViewModel (
}
}

fun switchCountDownTimer() {
val shouldWarn = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
private fun checkBatteryOptimizationSettings() : Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// can just check if the permission is set
!powerManager.isIgnoringBatteryOptimizations(getApplication<Application?>().packageName)
} else {
// is unable to change the battery permission for versions below M, so only false
false
}

if (!state.countDownTimerEnabled && shouldWarn) {
state.batteryWarningDialogVisible = true
} else {
state.countDownTimerEnabled = !state.countDownTimerEnabled
viewModelScope.launch {
userPreferencesRepository.updateCountDownEnabled(state.countDownTimerEnabled)
}
}
}

fun hideBatteryWarningModal() {
state.batteryWarningDialogVisible = false
private fun saveCountDownTimerEnabled(enabled: Boolean) {
viewModelScope.launch {
userPreferencesRepository.updateCountDownEnabled(enabled)
}
}

/**
Expand All @@ -177,7 +170,6 @@ class ClockPageViewModel (
Uri.parse("package:" + getApplication<Application?>().packageName)
startActivity(getApplication(), intentBatteryUsage, null)
}
hideBatteryWarningModal()
}

private fun timerTextFieldValuesToSeconds(): Int {
Expand Down Expand Up @@ -322,19 +314,20 @@ fun getCountDownSeconds(
* @param batteryWarningDialogVisible Determines if the battery warning dialog is visible
* @param countDownTimerEnabled Determines if the count down timer should be visible, allowing
* the user to set a time that an event will last.
* @param countDownEndTime Not sure if it'll be here in the future...
* @param currCountDownSeconds Not sure if this'll be here either...
* @param hoursTextFieldValue The text in the hours section of the EditTimerTextField
* @param minutesTextFieldValue The text in the minutes section of the EditTimerTextField. Should
* not exceed 59
* @param secondsTextFieldValue The text in the minutes section of the EditTimerTextField. Should
* not exceed 59
* @param batteryWarningConfirmFunction Fires when tapping confirm button in BatteryWarningDialog
* @param batteryWarningDismissFunction Fires when tapping outside the BatteryWarningDialog
* @param onTaskNameIconClick Fires when the icon in the TaskTextField is pushed. Changes from
* count up to count down mode.
* @param onDismissDropdown Fires when the dropdown in the TaskTextField is dismissed by tapping outside it
* @param onTimerAnimationFinish Fires when the count up timer fades in and out when starting recording
* @param checkBatteryOptimizationSettings Verifies whether or not the TimeClock has unrestricted
* battery permission. If it doesn't, then the battery warning dialog should appear.
* @param startBatteryManagementActivity Starts battery management activity
* @param saveCountDownTimerEnabledValue Saves the countDownTimerEnabled UserPreference variable, so
* the count down timer's visibility persists on activity recreation
* @param onDismissDropdown Fires when the dropdown in the TaskTextField is dismissed by
* tapping outside it
* @param onTimerAnimationFinish Fires when the count up timer fades in and out when starting
* recording
* @param onClockStart Fires when the start button is pressed
* @param onClockStop Fires when the stop button is pressed
*/
Expand All @@ -358,9 +351,9 @@ class ClockPageViewModelState(
text = "00",
selection = TextRange(0)
),
var batteryWarningConfirmFunction: () -> Unit = {},
var batteryWarningDismissFunction: () -> Unit = {},
var onTaskNameIconClick: () -> Unit = {},
var checkBatteryOptimizationSettings: () -> Boolean = {false},
var startBatteryManagementActivity: () -> Unit = {},
var saveCountDownTimerEnabledValue: (Boolean) -> Unit = {_ -> },
var onDismissDropdown: () -> Unit = {},
var onTimerAnimationFinish: () -> Unit = {},
var onClockStart: () -> Unit = {},
Expand Down Expand Up @@ -398,6 +391,25 @@ class ClockPageViewModelState(
// cheeky var used to prevent onTaskNameChange from being called after onDropdownMenuItemClick
var dropdownClicked = false

fun dismissBatteryWarningDialog() {
batteryWarningDialogVisible = false
}

fun confirmBatteryWarningDialog() {
startBatteryManagementActivity()
batteryWarningDialogVisible = false
}

fun onTaskTextFieldIconClick() {
val shouldWarn = checkBatteryOptimizationSettings()
if (!countDownTimerEnabled && shouldWarn) {
batteryWarningDialogVisible = true
} else {
countDownTimerEnabled = !countDownTimerEnabled
saveCountDownTimerEnabledValue(countDownTimerEnabled)
}
}

fun onTaskNameChange(tfv: TextFieldValue) {
if (dropdownClicked) {
dropdownClicked = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,4 +243,50 @@ class ClockPageViewModelStateTest {
)
)
}
}

@Test
fun confirmBatteryWarningDialog_callsStartBatteryManagementActivityFunction() {
var counter = 0
val testState = ClockPageViewModelState(
batteryWarningDialogVisible = true,
startBatteryManagementActivity = {
counter++
}
)
testState.confirmBatteryWarningDialog()
assertThat(counter).isEqualTo(1)
assertThat(testState.batteryWarningDialogVisible).isFalse()
}

@Test
fun dismissBatteryWarningDialog_dialogNotVisibleAfterDismiss() {
val testState = ClockPageViewModelState(
batteryWarningDialogVisible = true
)
testState.dismissBatteryWarningDialog()
assertThat(testState.batteryWarningDialogVisible).isFalse()
}

@Test
fun onTaskTextFieldIconClick_switchesCountDownTimerEnabled() {
var counter = 0
val testState = ClockPageViewModelState(
countDownTimerEnabled = false,
saveCountDownTimerEnabledValue = { counter++ }
)
testState.onTaskTextFieldIconClick()
assertThat(testState.countDownTimerEnabled).isTrue()
assertThat(counter).isEqualTo(1) // saveCountDownTimerEnabled has been called
}

@Test
fun onTaskTextFieldIconClick_shouldWarnIfBatterySettingsNotOptimized() {
val testState = ClockPageViewModelState(
checkBatteryOptimizationSettings = { true },
countDownTimerEnabled = false
)
testState.onTaskTextFieldIconClick()
assertThat(testState.countDownTimerEnabled).isFalse()
assertThat(testState.batteryWarningDialogVisible).isTrue()
}
}

0 comments on commit d99bb7a

Please sign in to comment.