Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -108,21 +108,21 @@ class AppNavigationTest {

// Start statistics screen.
onView(withId(R.id.nav_view))
.perform(navigateTo(R.id.statisticsFragment))
.perform(navigateTo(R.id.statistics_fragment_dest))

// Check that statistics screen was opened.
onView(withId(R.id.statistics)).check(matches(isDisplayed()))
onView(withId(R.id.statistics_layout)).check(matches(isDisplayed()))

onView(withId(R.id.drawer_layout))
.check(matches(isClosed(Gravity.START))) // Left Drawer should be closed.
.perform(open()) // Open Drawer

// Start tasks screen.
onView(withId(R.id.nav_view))
.perform(navigateTo(R.id.tasksFragment))
.perform(navigateTo(R.id.tasks_fragment_dest))

// Check that tasks screen was opened.
onView(withId(R.id.tasksContainer)).check(matches(isDisplayed()))
onView(withId(R.id.tasks_container_layout)).check(matches(isDisplayed()))
}

@Test
Expand Down Expand Up @@ -156,7 +156,7 @@ class AppNavigationTest {

// When the user navigates to the stats screen
activityScenario.onActivity {
it.findNavController(R.id.nav_host_fragment).navigate(R.id.statisticsFragment)
it.findNavController(R.id.nav_host_fragment).navigate(R.id.statistics_fragment_dest)
}

// Then check that left drawer is closed at startup
Expand Down Expand Up @@ -188,7 +188,7 @@ class AppNavigationTest {
// Click on the task on the list
onView(withText("UI <- button")).perform(click())
// Click on the edit task button
onView(withId(R.id.fab_edit_task)).perform(click())
onView(withId(R.id.edit_task_fab)).perform(click())

// Confirm that if we click "<-" once, we end up back at the task details page
onView(
Expand All @@ -197,7 +197,7 @@ class AppNavigationTest {
.getToolbarNavigationContentDescription()
)
).perform(click())
onView(withId(R.id.task_detail_title)).check(matches(isDisplayed()))
onView(withId(R.id.task_detail_title_text)).check(matches(isDisplayed()))

// Confirm that if we click "<-" a second time, we end up back at the home screen
onView(
Expand All @@ -206,7 +206,7 @@ class AppNavigationTest {
.getToolbarNavigationContentDescription()
)
).perform(click())
onView(withId(R.id.tasksContainer)).check(matches(isDisplayed()))
onView(withId(R.id.tasks_container_layout)).check(matches(isDisplayed()))
}

@Test
Expand All @@ -221,14 +221,14 @@ class AppNavigationTest {
// Click on the task on the list
onView(withText("Back button")).perform(click())
// Click on the edit task button
onView(withId(R.id.fab_edit_task)).perform(click())
onView(withId(R.id.edit_task_fab)).perform(click())

// Confirm that if we click back once, we end up back at the task details page
pressBack()
onView(withId(R.id.task_detail_title)).check(matches(isDisplayed()))
onView(withId(R.id.task_detail_title_text)).check(matches(isDisplayed()))

// Confirm that if we click back a second time, we end up back at the home screen
pressBack()
onView(withId(R.id.tasksContainer)).check(matches(isDisplayed()))
onView(withId(R.id.tasks_container_layout)).check(matches(isDisplayed()))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,15 @@ class TasksActivityTest {

// Click on the task on the list and verify that all the data is correct
onView(withText("TITLE1")).perform(click())
onView(withId(R.id.task_detail_title)).check(matches(withText("TITLE1")))
onView(withId(R.id.task_detail_description)).check(matches(withText("DESCRIPTION")))
onView(withId(R.id.task_detail_complete)).check(matches(not(isChecked())))
onView(withId(R.id.task_detail_title_text)).check(matches(withText("TITLE1")))
onView(withId(R.id.task_detail_description_text)).check(matches(withText("DESCRIPTION")))
onView(withId(R.id.task_detail_complete_checkbox)).check(matches(not(isChecked())))

// Click on the edit button, edit, and save
onView(withId(R.id.fab_edit_task)).perform(click())
onView(withId(R.id.add_task_title)).perform(replaceText("NEW TITLE"))
onView(withId(R.id.add_task_description)).perform(replaceText("NEW DESCRIPTION"))
onView(withId(R.id.fab_save_task)).perform(click())
onView(withId(R.id.edit_task_fab)).perform(click())
onView(withId(R.id.add_task_title_edit_text)).perform(replaceText("NEW TITLE"))
onView(withId(R.id.add_task_description_edit_text)).perform(replaceText("NEW DESCRIPTION"))
onView(withId(R.id.save_task_fab)).perform(click())

// Verify task is displayed on screen in the task list.
onView(withText("NEW TITLE")).check(matches(isDisplayed()))
Expand All @@ -130,10 +130,11 @@ class TasksActivityTest {
dataBindingIdlingResource.monitorActivity(activityScenario)

// Add active task
onView(withId(R.id.fab_add_task)).perform(click())
onView(withId(R.id.add_task_title)).perform(typeText("TITLE1"), closeSoftKeyboard())
onView(withId(R.id.add_task_description)).perform(typeText("DESCRIPTION"))
onView(withId(R.id.fab_save_task)).perform(click())
onView(withId(R.id.add_task_fab)).perform(click())
onView(withId(R.id.add_task_title_edit_text))
.perform(typeText("TITLE1"), closeSoftKeyboard())
onView(withId(R.id.add_task_description_edit_text)).perform(typeText("DESCRIPTION"))
onView(withId(R.id.save_task_fab)).perform(click())

// Open it in details view
onView(withText("TITLE1")).perform(click())
Expand Down Expand Up @@ -181,7 +182,7 @@ class TasksActivityTest {
onView(withText(taskTitle)).perform(click())

// Click on the checkbox in task details screen
onView(withId(R.id.task_detail_complete)).perform(click())
onView(withId(R.id.task_detail_complete_checkbox)).perform(click())

// Click on the navigation up button to go back to the list
onView(
Expand All @@ -191,7 +192,7 @@ class TasksActivityTest {
).perform(click())

// Check that the task is marked as completed
onView(allOf(withId(R.id.complete), hasSibling(withText(taskTitle))))
onView(allOf(withId(R.id.complete_checkbox), hasSibling(withText(taskTitle))))
.check(matches(isChecked()))
}

Expand All @@ -208,7 +209,7 @@ class TasksActivityTest {
// Click on the task on the list
onView(withText(taskTitle)).perform(click())
// Click on the checkbox in task details screen
onView(withId(R.id.task_detail_complete)).perform(click())
onView(withId(R.id.task_detail_complete_checkbox)).perform(click())

// Click on the navigation up button to go back to the list
onView(
Expand All @@ -218,7 +219,7 @@ class TasksActivityTest {
).perform(click())

// Check that the task is marked as active
onView(allOf(withId(R.id.complete), hasSibling(withText(taskTitle))))
onView(allOf(withId(R.id.complete_checkbox), hasSibling(withText(taskTitle))))
.check(matches(not(isChecked())))
}

Expand All @@ -235,9 +236,9 @@ class TasksActivityTest {
// Click on the task on the list
onView(withText(taskTitle)).perform(click())
// Click on the checkbox in task details screen
onView(withId(R.id.task_detail_complete)).perform(click())
onView(withId(R.id.task_detail_complete_checkbox)).perform(click())
// Click again to restore it to original state
onView(withId(R.id.task_detail_complete)).perform(click())
onView(withId(R.id.task_detail_complete_checkbox)).perform(click())

// Click on the navigation up button to go back to the list
onView(
Expand All @@ -247,7 +248,7 @@ class TasksActivityTest {
).perform(click())

// Check that the task is marked as active
onView(allOf(withId(R.id.complete), hasSibling(withText(taskTitle))))
onView(allOf(withId(R.id.complete_checkbox), hasSibling(withText(taskTitle))))
.check(matches(not(isChecked())))
}

Expand All @@ -264,9 +265,9 @@ class TasksActivityTest {
// Click on the task on the list
onView(withText(taskTitle)).perform(click())
// Click on the checkbox in task details screen
onView(withId(R.id.task_detail_complete)).perform(click())
onView(withId(R.id.task_detail_complete_checkbox)).perform(click())
// Click again to restore it to original state
onView(withId(R.id.task_detail_complete)).perform(click())
onView(withId(R.id.task_detail_complete_checkbox)).perform(click())

// Click on the navigation up button to go back to the list
onView(
Expand All @@ -276,7 +277,7 @@ class TasksActivityTest {
).perform(click())

// Check that the task is marked as active
onView(allOf(withId(R.id.complete), hasSibling(withText(taskTitle))))
onView(allOf(withId(R.id.complete_checkbox), hasSibling(withText(taskTitle))))
.check(matches(isChecked()))
}

Expand All @@ -287,10 +288,11 @@ class TasksActivityTest {
dataBindingIdlingResource.monitorActivity(activityScenario)

// Click on the "+" button, add details, and save
onView(withId(R.id.fab_add_task)).perform(click())
onView(withId(R.id.add_task_title)).perform(typeText("title"), closeSoftKeyboard())
onView(withId(R.id.add_task_description)).perform(typeText("description"))
onView(withId(R.id.fab_save_task)).perform(click())
onView(withId(R.id.add_task_fab)).perform(click())
onView(withId(R.id.add_task_title_edit_text))
.perform(typeText("title"), closeSoftKeyboard())
onView(withId(R.id.add_task_description_edit_text)).perform(typeText("description"))
onView(withId(R.id.save_task_fab)).perform(click())

// Then verify task is displayed on screen
onView(withText("title")).check(matches(isDisplayed()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import androidx.lifecycle.Observer
*/
open class Event<out T>(private val content: T) {

@Suppress("MemberVisibilityCanBePrivate")
var hasBeenHandled = false
private set // Allow external read but not write

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ import com.example.android.architecture.blueprints.todoapp.tasks.ADD_EDIT_RESULT
import com.example.android.architecture.blueprints.todoapp.util.setupRefreshLayout
import com.example.android.architecture.blueprints.todoapp.util.setupSnackbar
import com.google.android.material.snackbar.Snackbar
import dagger.android.support.DaggerFragment
import javax.inject.Inject
import dagger.android.support.DaggerFragment

/**
* Main UI for the add task screen. Users can enter a task title and description.
Expand Down Expand Up @@ -69,7 +69,7 @@ class AddEditTaskFragment : DaggerFragment() {
}

private fun setupSnackbar() {
view?.setupSnackbar(this, viewModel.snackbarMessage, Snackbar.LENGTH_SHORT)
view?.setupSnackbar(this, viewModel.snackbarText, Snackbar.LENGTH_SHORT)
}

private fun setupNavigation() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ class AddEditTaskViewModel @Inject constructor(
val dataLoading: LiveData<Boolean> = _dataLoading

private val _snackbarText = MutableLiveData<Event<Int>>()
val snackbarMessage: LiveData<Event<Int>> = _snackbarText
val snackbarText: LiveData<Event<Int>> = _snackbarText

private val _taskUpdated = MutableLiveData<Event<Unit>>()
val taskUpdatedEvent: LiveData<Event<Unit>> = _taskUpdated
private val _taskUpdatedEvent = MutableLiveData<Event<Unit>>()
val taskUpdatedEvent: LiveData<Event<Unit>> = _taskUpdatedEvent

private var taskId: String? = null

Expand Down Expand Up @@ -125,7 +125,7 @@ class AddEditTaskViewModel @Inject constructor(

private fun createTask(newTask: Task) = viewModelScope.launch {
tasksRepository.saveTask(newTask)
_taskUpdated.value = Event(Unit)
_taskUpdatedEvent.value = Event(Unit)
}

private fun updateTask(task: Task) {
Expand All @@ -134,7 +134,7 @@ class AddEditTaskViewModel @Inject constructor(
}
viewModelScope.launch {
tasksRepository.saveTask(task)
_taskUpdated.value = Event(Unit)
_taskUpdatedEvent.value = Event(Unit)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,25 +36,14 @@ object TasksRemoteDataSource : TasksDataSource {
addTask("Finish bridge in Tacoma", "Found awesome girders at half the cost!")
}

/**
* Note: [LoadTasksCallback.onDataNotAvailable] is never fired. In a real remote data
* source implementation, this would be fired if the server can't be contacted or the server
* returns an error.
*/
override suspend fun getTasks(): Result<List<Task>> {
// Simulate network by delaying the execution.
val tasks = TASKS_SERVICE_DATA.values.toList()
delay(SERVICE_LATENCY_IN_MILLIS)
return Success(tasks)
}

/**
* Note: [GetTaskCallback.onDataNotAvailable] is never fired. In a real remote data
* source implementation, this would be fired if the server can't be contacted or the server
* returns an error.
*/
override suspend fun getTask(taskId: String): Result<Task> {

// Simulate network by delaying the execution.
delay(SERVICE_LATENCY_IN_MILLIS)
TASKS_SERVICE_DATA[taskId]?.let {
Expand All @@ -65,31 +54,29 @@ object TasksRemoteDataSource : TasksDataSource {

private fun addTask(title: String, description: String) {
val newTask = Task(title, description)
TASKS_SERVICE_DATA.put(newTask.id, newTask)
TASKS_SERVICE_DATA[newTask.id] = newTask
}

override suspend fun saveTask(task: Task) {
TASKS_SERVICE_DATA.put(task.id, task)
TASKS_SERVICE_DATA[task.id] = task
}

override suspend fun completeTask(task: Task) {
val completedTask = Task(task.title, task.description, true, task.id)
TASKS_SERVICE_DATA.put(task.id, completedTask)
TASKS_SERVICE_DATA[task.id] = completedTask
}

override suspend fun completeTask(taskId: String) {
// Not required for the remote data source because the {@link DefaultTasksRepository} handles
// converting from a {@code taskId} to a {@link task} using its cached data.
// Not required for the remote data source
}

override suspend fun activateTask(task: Task) {
val activeTask = Task(task.title, task.description, false, task.id)
TASKS_SERVICE_DATA.put(task.id, activeTask)
TASKS_SERVICE_DATA[task.id] = activeTask
}

override suspend fun activateTask(taskId: String) {
// Not required for the remote data source because the {@link DefaultTasksRepository} handles
// converting from a {@code taskId} to a {@link task} using its cached data.
// Not required for the remote data source
}

override suspend fun clearCompletedTasks() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class StatisticsFragment : DaggerFragment() {
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory

private val statisticsViewModel by viewModels<StatisticsViewModel> { viewModelFactory }
private val viewModel by viewModels<StatisticsViewModel> { viewModelFactory }

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
Expand All @@ -53,9 +53,9 @@ class StatisticsFragment : DaggerFragment() {

override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewDataBinding.viewmodel = statisticsViewModel
viewDataBinding.viewmodel = viewModel
viewDataBinding.lifecycleOwner = this.viewLifecycleOwner
this.setupRefreshLayout(viewDataBinding.refreshLayout)
statisticsViewModel.start()
viewModel.start()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,18 @@ class TaskDetailFragment : DaggerFragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setupFab()
view?.setupSnackbar(this, viewModel.snackbarMessage, Snackbar.LENGTH_SHORT)
view?.setupSnackbar(this, viewModel.snackbarText, Snackbar.LENGTH_SHORT)
setupNavigation()
this.setupRefreshLayout(viewDataBinding.refreshLayout)
}

private fun setupNavigation() {
viewModel.deleteTaskCommand.observe(this, EventObserver {
viewModel.deleteTaskEvent.observe(this, EventObserver {
val action = TaskDetailFragmentDirections
.actionTaskDetailFragmentToTasksFragment(DELETE_RESULT_OK)
findNavController().navigate(action)
})
viewModel.editTaskCommand.observe(this, EventObserver {
viewModel.editTaskEvent.observe(this, EventObserver {
val action = TaskDetailFragmentDirections
.actionTaskDetailFragmentToAddEditTaskFragment(
args.taskId,
Expand All @@ -74,7 +74,7 @@ class TaskDetailFragment : DaggerFragment() {
}

private fun setupFab() {
activity?.findViewById<View>(R.id.fab_edit_task)?.setOnClickListener {
activity?.findViewById<View>(R.id.edit_task_fab)?.setOnClickListener {
viewModel.editTask()
}
}
Expand Down
Loading