Skip to content

Commit 515e82c

Browse files
committed
Fixes repository errors, tests, creation of database
1 parent 096b32e commit 515e82c

File tree

17 files changed

+151
-165
lines changed

17 files changed

+151
-165
lines changed

app/src/main/java/com/example/android/architecture/blueprints/todoapp/data/source/DefaultTasksRepository.kt

Lines changed: 13 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -87,32 +87,24 @@ class DefaultTasksRepository(
8787
* Relies on [getTasks] to fetch data and picks the task with the same ID.
8888
*/
8989
override suspend fun getTask(taskId: String, forceUpdate: Boolean): Result<Task> {
90-
9190
if (forceUpdate) {
9291
updateTaskFromRemoteDataSource(taskId)
9392
}
9493
return tasksLocalDataSource.getTask(taskId)
9594
}
9695

9796
override suspend fun saveTask(task: Task) {
98-
// Do in memory cache update to keep the app UI up to date
99-
// cacheAndPerform(task) {
100-
coroutineScope {
101-
launch { tasksRemoteDataSource.saveTask(task) }
102-
launch { tasksLocalDataSource.saveTask(task) }
103-
}
104-
// }
97+
coroutineScope {
98+
launch { tasksRemoteDataSource.saveTask(task) }
99+
launch { tasksLocalDataSource.saveTask(task) }
100+
}
105101
}
106102

107103
override suspend fun completeTask(task: Task) {
108-
// Do in memory cache update to keep the app UI up to date
109-
// cacheAndPerform(task) {
110-
task.isCompleted = true
111-
coroutineScope {
112-
launch { tasksRemoteDataSource.completeTask(task) }
113-
launch { tasksLocalDataSource.completeTask(task) }
114-
}
115-
// }
104+
coroutineScope {
105+
launch { tasksRemoteDataSource.completeTask(task) }
106+
launch { tasksLocalDataSource.completeTask(task) }
107+
}
116108
}
117109

118110
override suspend fun completeTask(taskId: String) {
@@ -124,15 +116,10 @@ class DefaultTasksRepository(
124116
}
125117

126118
override suspend fun activateTask(task: Task) = withContext<Unit>(ioDispatcher) {
127-
// Do in memory cache update to keep the app UI up to date
128-
// cacheAndPerform(task) {
129-
task.isCompleted = false
130-
coroutineScope {
131-
launch { tasksRemoteDataSource.activateTask(task) }
132-
launch { tasksLocalDataSource.activateTask(task) }
133-
}
134-
135-
// }
119+
coroutineScope {
120+
launch { tasksRemoteDataSource.activateTask(task) }
121+
launch { tasksLocalDataSource.activateTask(task) }
122+
}
136123
}
137124

138125
override suspend fun activateTask(taskId: String) {
@@ -148,9 +135,6 @@ class DefaultTasksRepository(
148135
launch { tasksRemoteDataSource.clearCompletedTasks() }
149136
launch { tasksLocalDataSource.clearCompletedTasks() }
150137
}
151-
// withContext(ioDispatcher) {
152-
// cachedTasks?.entries?.removeAll { it.value.isCompleted }
153-
// }
154138
}
155139

156140
override suspend fun deleteAllTasks() {
@@ -160,53 +144,16 @@ class DefaultTasksRepository(
160144
launch { tasksLocalDataSource.deleteAllTasks() }
161145
}
162146
}
163-
// cachedTasks?.clear()
164147
}
165148

166149
override suspend fun deleteTask(taskId: String) {
167150
coroutineScope {
168151
launch { tasksRemoteDataSource.deleteTask(taskId) }
169152
launch { tasksLocalDataSource.deleteTask(taskId) }
170153
}
171-
172-
// cachedTasks?.remove(taskId)
173-
Unit // Force return type
174-
}
175-
//
176-
// private fun refreshCache(tasks: List<Task>) {
177-
//// cachedTasks?.clear()
178-
// tasks.sortedBy { it.id }.forEach {
179-
// cacheAndPerform(it) {}
180-
// }
181-
// }
182-
//
183-
// private suspend fun refreshLocalDataSource(tasks: List<Task>) {
184-
// tasksLocalDataSource.deleteAllTasks()
185-
// for (task in tasks) {
186-
// tasksLocalDataSource.saveTask(task)
187-
// }
188-
// }
189-
//
190-
// private suspend fun refreshLocalDataSource(task: Task) {
191-
// tasksLocalDataSource.saveTask(task)
192-
// }
154+
}
193155

194156
private suspend fun getTaskWithId(id: String): Result<Task> {
195157
return tasksLocalDataSource.getTask(id)
196158
}
197-
//
198-
// private fun cacheTask(task: Task): Task {
199-
// val cachedTask = Task(task.title, task.description, task.isCompleted, task.id)
200-
// // Create if it doesn't exist.
201-
// if (cachedTasks == null) {
202-
// cachedTasks = ConcurrentHashMap()
203-
// }
204-
// cachedTasks?.put(cachedTask.id, cachedTask)
205-
// return cachedTask
206-
// }
207-
//
208-
// private inline fun cacheAndPerform(task: Task, perform: (Task) -> Unit) {
209-
// val cachedTask = cacheTask(task)
210-
// perform(cachedTask)
211-
// }
212159
}

app/src/main/java/com/example/android/architecture/blueprints/todoapp/data/source/local/TasksDao.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import com.example.android.architecture.blueprints.todoapp.data.Task
3131
interface TasksDao {
3232

3333
/**
34-
* Observes list of tasks. Not using the Paging library for simplicity.
34+
* Observes list of tasks.
3535
*
3636
* @return all tasks.
3737
*/

app/src/main/java/com/example/android/architecture/blueprints/todoapp/statistics/StatisticsFragment.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,5 @@ class StatisticsFragment : Fragment() {
5252
viewDataBinding.viewmodel = statisticsViewModel
5353
viewDataBinding.lifecycleOwner = this.viewLifecycleOwner
5454
this.setupRefreshLayout(viewDataBinding.refreshLayout)
55-
statisticsViewModel.start()
5655
}
5756
}

app/src/main/java/com/example/android/architecture/blueprints/todoapp/taskdetail/TaskDetailViewModel.kt

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,10 @@ class TaskDetailViewModel(
4242

4343
private val _task = _params.switchMap { (taskId, forceUpdate) ->
4444
if (forceUpdate) {
45+
_dataLoading.value = true
4546
viewModelScope.launch {
4647
tasksRepository.refreshTasks()
48+
_dataLoading.value = false
4749
}
4850
}
4951
tasksRepository.observeTask(taskId).switchMap { computeResult(it) }
@@ -93,24 +95,21 @@ class TaskDetailViewModel(
9395
}
9496
}
9597

96-
fun start(taskId: String?, forceRefresh: Boolean = true) {
97-
if (_isDataAvailable.value == true && !forceRefresh || _dataLoading.value == true) {
98+
fun start(taskId: String?) {
99+
// If we're already loading or already loaded, return (might be a config change)
100+
if (_dataLoading.value == true || taskId == _params.value?.first) {
98101
return
99102
}
100103
if (taskId == null) {
101104
_isDataAvailable.value = false
102105
return
103106
}
104107

105-
// Show loading indicator
106-
_dataLoading.value = true
107-
108-
_params.value = Pair(taskId, forceRefresh)
108+
_params.value = Pair(taskId, false)
109109
}
110110

111111
private fun computeResult(taskResult: Result<Task>): LiveData<Task> {
112112

113-
_dataLoading.value = true
114113
// TODO: This is a good case for liveData builder. Replace when stable.
115114
val result = MutableLiveData<Task>()
116115

@@ -123,7 +122,6 @@ class TaskDetailViewModel(
123122
_isDataAvailable.value = false
124123
}
125124

126-
_dataLoading.value = false
127125
return result
128126
}
129127

app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksFragment.kt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,6 @@ class TasksFragment : Fragment() {
9494
setupRefreshLayout(viewDataBinding.refreshLayout, viewDataBinding.tasksList)
9595
setupNavigation()
9696
setupFab()
97-
98-
// Always reloading data for simplicity. Real apps should only do this on first load and
99-
// when navigating back to this destination. TODO: https://issuetracker.google.com/79672220
100-
viewModel.loadTasks(true)
10197
}
10298

10399
private fun setupNavigation() {
@@ -129,7 +125,6 @@ class TasksFragment : Fragment() {
129125
else -> TasksFilterType.ALL_TASKS
130126
}
131127
)
132-
viewModel.loadTasks(false)
133128
true
134129
}
135130
show()

app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksListBindings.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,14 @@
1515
*/
1616
package com.example.android.architecture.blueprints.todoapp.tasks
1717

18+
import android.graphics.Paint
19+
import android.widget.TextView
1820
import androidx.databinding.BindingAdapter
1921
import androidx.recyclerview.widget.RecyclerView
2022
import com.example.android.architecture.blueprints.todoapp.data.Task
2123

24+
25+
2226
/**
2327
* [BindingAdapter]s for the [Task]s list.
2428
*/
@@ -28,3 +32,12 @@ fun setItems(listView: RecyclerView, items: List<Task>?) {
2832
(listView.adapter as TasksAdapter).submitList(items)
2933
}
3034
}
35+
36+
@BindingAdapter("app:completedTask")
37+
fun setStyle(textView: TextView, enabled: Boolean) {
38+
if (enabled) {
39+
textView.paintFlags = textView.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
40+
} else {
41+
textView.paintFlags = textView.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
42+
}
43+
}

app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksViewModel.kt

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,10 @@ class TasksViewModel(
4343

4444
private val _items: LiveData<List<Task>> = _forceUpdate.switchMap { forceUpdate ->
4545
if (forceUpdate) {
46+
_dataLoading.value = true
4647
viewModelScope.launch {
4748
tasksRepository.refreshTasks()
49+
_dataLoading.value = false
4850
}
4951
}
5052
tasksRepository.observeTasks().switchMap { filterTasks(it) }
@@ -82,7 +84,7 @@ class TasksViewModel(
8284
private val _newTaskEvent = MutableLiveData<Event<Unit>>()
8385
val newTaskEvent: LiveData<Event<Unit>> = _newTaskEvent
8486

85-
private var resultMessageShown: Boolean = true
87+
private var resultMessageShown: Boolean = false
8688

8789
// This LiveData depends on another so we can use a transformation.
8890
val empty: LiveData<Boolean> = Transformations.map(_items) {
@@ -126,6 +128,8 @@ class TasksViewModel(
126128
)
127129
}
128130
}
131+
// Refresh list
132+
loadTasks(false)
129133
}
130134

131135
private fun setFilter(
@@ -142,8 +146,6 @@ class TasksViewModel(
142146
viewModelScope.launch {
143147
tasksRepository.clearCompletedTasks()
144148
showSnackbarMessage(R.string.completed_tasks_cleared)
145-
// Refresh list to show the new state
146-
loadTasks(false)
147149
}
148150
}
149151

@@ -155,8 +157,6 @@ class TasksViewModel(
155157
tasksRepository.activateTask(task)
156158
showSnackbarMessage(R.string.task_marked_active)
157159
}
158-
// Refresh list to show the new state
159-
loadTasks(false)
160160
}
161161

162162
/**
@@ -188,7 +188,6 @@ class TasksViewModel(
188188
}
189189

190190
private fun filterTasks(tasksResult: Result<List<Task>>): LiveData<List<Task>> {
191-
_dataLoading.value = true
192191
// TODO: This is a good case for liveData builder. Replace when stable.
193192
val result = MutableLiveData<List<Task>>()
194193

@@ -203,7 +202,6 @@ class TasksViewModel(
203202
isDataLoadingError.value = true
204203
}
205204

206-
_dataLoading.value = false
207205
return result
208206
}
209207

@@ -214,7 +212,7 @@ class TasksViewModel(
214212
_forceUpdate.value = forceUpdate
215213
}
216214

217-
private suspend fun filterItems(tasks: List<Task>, filteringType: TasksFilterType): List<Task> {
215+
private fun filterItems(tasks: List<Task>, filteringType: TasksFilterType): List<Task> {
218216
val tasksToShow = ArrayList<Task>()
219217
// We filter the tasks based on the requestType
220218
for (task in tasks) {

app/src/main/res/layout/task_item.xml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
~ See the License for the specific language governing permissions and
1414
~ limitations under the License.
1515
-->
16-
<layout xmlns:android="http://schemas.android.com/apk/res/android">
16+
<layout xmlns:android="http://schemas.android.com/apk/res/android"
17+
xmlns:app="http://schemas.android.com/apk/res-auto">
1718

1819
<data>
1920

@@ -31,7 +32,6 @@
3132
<LinearLayout
3233
android:layout_width="match_parent"
3334
android:layout_height="?android:attr/listPreferredItemHeight"
34-
android:background="@{task.completed ? @drawable/list_completed_touch_feedback : @drawable/touch_feedback}"
3535
android:orientation="horizontal"
3636
android:paddingLeft="@dimen/activity_horizontal_margin"
3737
android:paddingRight="@dimen/activity_horizontal_margin"
@@ -54,6 +54,7 @@
5454
android:layout_gravity="center_vertical"
5555
android:layout_marginLeft="@dimen/activity_horizontal_margin"
5656
android:textAppearance="@style/TextAppearance.AppCompat.Title"
57-
android:text="@{task.titleForList}" />
57+
android:text="@{task.titleForList}"
58+
app:completedTask="@{task.completed}" />
5859
</LinearLayout>
5960
</layout>

app/src/main/res/navigation/nav_graph.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
<action
4242
android:id="@+id/action_statisticsFragment_to_tasksFragment"
4343
app:destination="@id/tasksFragment"
44-
app:popUpTo="@+id/tasksFragment" />
44+
/>
4545
</fragment>
4646
<fragment
4747
android:id="@+id/tasksFragment"
@@ -76,7 +76,7 @@
7676
<action
7777
android:id="@+id/action_addEditTaskFragment_to_tasksFragment"
7878
app:destination="@id/tasksFragment"
79-
app:popUpTo="@+id/tasksFragment" />
79+
/>
8080
</fragment>
8181
<argument
8282
android:name="userMessage"

app/src/prod/java/com/example/android/architecture/blueprints/todoapp/ServiceLocator.kt

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import android.content.Context
2020
import androidx.annotation.VisibleForTesting
2121
import androidx.room.Room
2222
import com.example.android.architecture.blueprints.todoapp.data.source.DefaultTasksRepository
23+
import com.example.android.architecture.blueprints.todoapp.data.source.TasksDataSource
2324
import com.example.android.architecture.blueprints.todoapp.data.source.TasksRepository
2425
import com.example.android.architecture.blueprints.todoapp.data.source.local.TasksLocalDataSource
2526
import com.example.android.architecture.blueprints.todoapp.data.source.local.ToDoDatabase
@@ -45,16 +46,21 @@ object ServiceLocator {
4546
}
4647

4748
private fun createTasksRepository(context: Context): TasksRepository {
48-
database = Room.databaseBuilder(
49+
return DefaultTasksRepository(TasksRemoteDataSource, createTaskLocalDataSource(context))
50+
}
51+
52+
private fun createTaskLocalDataSource(context: Context): TasksDataSource {
53+
val database = database ?: createDataBase(context)
54+
return TasksLocalDataSource(database.taskDao())
55+
}
56+
57+
private fun createDataBase(context: Context): ToDoDatabase {
58+
val result = Room.databaseBuilder(
4959
context.applicationContext,
5060
ToDoDatabase::class.java, "Tasks.db"
51-
)
52-
.build()
53-
54-
return DefaultTasksRepository(
55-
TasksRemoteDataSource,
56-
TasksLocalDataSource(database!!.taskDao())
57-
)
61+
).build()
62+
database = result
63+
return result
5864
}
5965

6066
@VisibleForTesting

0 commit comments

Comments
 (0)