|
16 | 16 | package com.google.firebase.dataconnect.minimaldemo |
17 | 17 |
|
18 | 18 | import android.os.Bundle |
19 | | -import android.view.Menu |
20 | | -import android.view.MenuItem |
21 | | -import android.widget.CompoundButton.OnCheckedChangeListener |
| 19 | +import android.view.View |
22 | 20 | import androidx.activity.viewModels |
23 | 21 | import androidx.appcompat.app.AppCompatActivity |
24 | | -import androidx.lifecycle.Lifecycle |
25 | 22 | import androidx.lifecycle.flowWithLifecycle |
26 | 23 | import androidx.lifecycle.lifecycleScope |
27 | | -import com.google.firebase.dataconnect.minimaldemo.ListItemsViewModel.OperationState |
28 | | -import com.google.firebase.dataconnect.minimaldemo.databinding.ActivityMainBinding |
| 24 | +import com.google.firebase.dataconnect.minimaldemo.databinding.ActivityListItemsBinding |
29 | 25 | import kotlinx.coroutines.flow.collectLatest |
30 | 26 | import kotlinx.coroutines.launch |
31 | 27 |
|
32 | 28 | class ListItemsActivity : AppCompatActivity() { |
33 | 29 |
|
34 | 30 | private lateinit var myApplication: MyApplication |
35 | | - private lateinit var viewBinding: ActivityMainBinding |
| 31 | + private lateinit var viewBinding: ActivityListItemsBinding |
36 | 32 | private val viewModel: ListItemsViewModel by viewModels { ListItemsViewModel.Factory } |
37 | 33 |
|
38 | 34 | override fun onCreate(savedInstanceState: Bundle?) { |
39 | 35 | super.onCreate(savedInstanceState) |
40 | 36 | myApplication = application as MyApplication |
41 | 37 |
|
42 | | - viewBinding = ActivityMainBinding.inflate(layoutInflater) |
| 38 | + viewBinding = ActivityListItemsBinding.inflate(layoutInflater) |
43 | 39 | setContentView(viewBinding.root) |
44 | 40 |
|
45 | | - viewBinding.insertItemButton.setOnClickListener { viewModel.insertItem() } |
46 | | - viewBinding.getItemButton.setOnClickListener { viewModel.getItem() } |
47 | | - viewBinding.deleteItemButton.setOnClickListener { viewModel.deleteItem() } |
48 | | - viewBinding.useEmulatorCheckBox.setOnCheckedChangeListener(useEmulatorOnCheckedChangeListener) |
49 | | - viewBinding.debugLoggingCheckBox.setOnCheckedChangeListener(debugLoggingOnCheckedChangeListener) |
50 | | - |
51 | 41 | lifecycleScope.launch { |
| 42 | + if (viewModel.loadingState == ListItemsViewModel.LoadingState.NotStarted) { |
| 43 | + viewModel.getItems() |
| 44 | + } |
52 | 45 | viewModel.stateSequenceNumber.flowWithLifecycle(lifecycle).collectLatest { |
53 | 46 | onViewModelStateChange() |
54 | 47 | } |
55 | 48 | } |
56 | 49 | } |
57 | 50 |
|
58 | | - override fun onCreateOptionsMenu(menu: Menu?): Boolean { |
59 | | - menuInflater.inflate(R.menu.menu_main, menu) |
60 | | - return true |
61 | | - } |
62 | | - |
63 | | - override fun onOptionsItemSelected(item: MenuItem): Boolean { |
64 | | - return super.onOptionsItemSelected(item) |
65 | | - } |
66 | | - |
67 | | - override fun onResume() { |
68 | | - super.onResume() |
69 | | - lifecycleScope.launch { |
70 | | - viewBinding.useEmulatorCheckBox.isChecked = myApplication.getUseDataConnectEmulator() |
71 | | - viewBinding.debugLoggingCheckBox.isChecked = myApplication.getDataConnectDebugLoggingEnabled() |
72 | | - } |
73 | | - } |
74 | | - |
75 | 51 | private fun onViewModelStateChange() { |
76 | | - viewBinding.progressText.text = viewModel.progressText |
77 | | - viewBinding.insertItemButton.isEnabled = !viewModel.isInsertOperationInProgress |
78 | | - viewBinding.getItemButton.isEnabled = |
79 | | - viewModel.isGetOperationRunnable && !viewModel.isGetOperationInProgress |
80 | | - viewBinding.deleteItemButton.isEnabled = |
81 | | - viewModel.isDeleteOperationRunnable && !viewModel.isDeleteOperationInProgress |
82 | | - } |
83 | | - |
84 | | - private val debugLoggingOnCheckedChangeListener = OnCheckedChangeListener { _, isChecked -> |
85 | | - if (!lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) { |
86 | | - return@OnCheckedChangeListener |
87 | | - } |
88 | | - myApplication.coroutineScope.launch { |
89 | | - myApplication.setDataConnectDebugLoggingEnabled(isChecked) |
| 52 | + val items = viewModel.result?.getOrNull() |
| 53 | + val exception = viewModel.result?.exceptionOrNull() |
| 54 | + val loadingState = viewModel.loadingState |
| 55 | + |
| 56 | + if (loadingState == ListItemsViewModel.LoadingState.InProgress) { |
| 57 | + viewBinding.statusText.text = "Loading Items..." |
| 58 | + viewBinding.statusText.visibility = View.VISIBLE |
| 59 | + viewBinding.recyclerView.visibility = View.GONE |
| 60 | + } else if (items !== null) { |
| 61 | + viewBinding.statusText.text = "Items: $items" |
| 62 | + viewBinding.statusText.visibility = View.VISIBLE |
| 63 | + viewBinding.recyclerView.visibility = View.GONE |
| 64 | + } else if (exception !== null) { |
| 65 | + viewBinding.statusText.text = "Loading items FAILED: $exception" |
| 66 | + viewBinding.statusText.visibility = View.VISIBLE |
| 67 | + viewBinding.recyclerView.visibility = View.GONE |
| 68 | + } else { |
| 69 | + viewBinding.statusText.text = null |
| 70 | + viewBinding.statusText.visibility = View.GONE |
| 71 | + viewBinding.recyclerView.visibility = View.GONE |
90 | 72 | } |
91 | 73 | } |
92 | | - |
93 | | - private val useEmulatorOnCheckedChangeListener = OnCheckedChangeListener { _, isChecked -> |
94 | | - if (!lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) { |
95 | | - return@OnCheckedChangeListener |
96 | | - } |
97 | | - myApplication.coroutineScope.launch { myApplication.setUseDataConnectEmulator(isChecked) } |
98 | | - } |
99 | | - |
100 | | - companion object { |
101 | | - |
102 | | - private val ListItemsViewModel.isInsertOperationInProgress: Boolean |
103 | | - get() = insertState is OperationState.InProgress |
104 | | - |
105 | | - private val ListItemsViewModel.isGetOperationInProgress: Boolean |
106 | | - get() = getState is OperationState.InProgress |
107 | | - |
108 | | - private val ListItemsViewModel.isDeleteOperationInProgress: Boolean |
109 | | - get() = deleteState is OperationState.InProgress |
110 | | - |
111 | | - private val ListItemsViewModel.isGetOperationRunnable: Boolean |
112 | | - get() = lastInsertedKey !== null |
113 | | - |
114 | | - private val ListItemsViewModel.isDeleteOperationRunnable: Boolean |
115 | | - get() = lastInsertedKey !== null |
116 | | - |
117 | | - private val ListItemsViewModel.progressText: String? |
118 | | - get() { |
119 | | - // Save properties to local variables to enable Kotlin's type narrowing in the "if" blocks |
120 | | - // below. |
121 | | - val insertState = insertState |
122 | | - val getState = getState |
123 | | - val deleteState = deleteState |
124 | | - val state = |
125 | | - listOfNotNull(insertState, getState, deleteState).maxByOrNull { it.sequenceNumber } |
126 | | - |
127 | | - return if (state === null) { |
128 | | - null |
129 | | - } else if (state === insertState) { |
130 | | - when (insertState) { |
131 | | - is OperationState.InProgress -> |
132 | | - "Inserting item: ${insertState.variables.toDisplayString()}" |
133 | | - is OperationState.Completed -> |
134 | | - insertState.result.fold( |
135 | | - onSuccess = { |
136 | | - "Inserted item with id=${it.id}:\n${insertState.variables.toDisplayString()}" |
137 | | - }, |
138 | | - onFailure = { "Inserting item ${insertState.variables} FAILED: $it" }, |
139 | | - ) |
140 | | - } |
141 | | - } else if (state === getState) { |
142 | | - when (getState) { |
143 | | - is OperationState.InProgress -> "Retrieving item with ID ${getState.variables.id}..." |
144 | | - is OperationState.Completed -> |
145 | | - getState.result.fold( |
146 | | - onSuccess = { |
147 | | - "Retrieved item with ID ${getState.variables.id}:\n${it?.toDisplayString()}" |
148 | | - }, |
149 | | - onFailure = { "Retrieving item with ID ${getState.variables.id} FAILED: $it" }, |
150 | | - ) |
151 | | - } |
152 | | - } else if (state === deleteState) { |
153 | | - when (deleteState) { |
154 | | - is OperationState.InProgress -> "Deleting item with ID ${deleteState.variables.id}..." |
155 | | - is OperationState.Completed -> |
156 | | - deleteState.result.fold( |
157 | | - onSuccess = { "Deleted item with ID ${deleteState.variables.id}" }, |
158 | | - onFailure = { "Deleting item with ID ${deleteState.variables.id} FAILED: $it" }, |
159 | | - ) |
160 | | - } |
161 | | - } else { |
162 | | - throw RuntimeException("internal error: unknown state: $state (error code vp4rjptx6r)") |
163 | | - } |
164 | | - } |
165 | | - } |
166 | 74 | } |
0 commit comments