Skip to content

Commit 77cca29

Browse files
committed
add delete button
1 parent 5fdc879 commit 77cca29

File tree

3 files changed

+106
-15
lines changed

3 files changed

+106
-15
lines changed

firebase-dataconnect/demo/firebase/dataconnect/connector/operations.gql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ query GetItemByKey(
4949
}
5050
}
5151

52+
mutation DeleteItemByKey(
53+
$key: zwda6x9zyy_Key!
54+
) @auth(level: PUBLIC) {
55+
zwda6x9zyy_delete(key: $key)
56+
}
57+
5258
# This mutation exists only as a workaround for b/382688278 where the following
5359
# compiler error will otherwise result when compiling the generated code:
5460
# Serializer has not been found for type 'java.util.UUID'. To use context

firebase-dataconnect/demo/src/main/kotlin/com/google/firebase/dataconnect/minimaldemo/MainActivityViewModel.kt

Lines changed: 89 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.AP
2222
import androidx.lifecycle.viewModelScope
2323
import androidx.lifecycle.viewmodel.initializer
2424
import androidx.lifecycle.viewmodel.viewModelFactory
25+
import com.google.firebase.dataconnect.minimaldemo.connector.DeleteItemByKeyMutation
2526
import com.google.firebase.dataconnect.minimaldemo.connector.GetItemByKeyQuery
2627
import com.google.firebase.dataconnect.minimaldemo.connector.InsertItemMutation
2728
import com.google.firebase.dataconnect.minimaldemo.connector.Zwda6x9zyyKey
@@ -33,6 +34,7 @@ import java.util.Objects
3334
import kotlinx.coroutines.CoroutineStart
3435
import kotlinx.coroutines.Deferred
3536
import kotlinx.coroutines.ExperimentalCoroutinesApi
37+
import kotlinx.coroutines.Job
3638
import kotlinx.coroutines.async
3739
import kotlinx.coroutines.flow.MutableStateFlow
3840
import kotlinx.coroutines.flow.StateFlow
@@ -46,6 +48,7 @@ class MainActivityViewModel(private val app: MyApplication) : ViewModel() {
4648
State(
4749
insertItem = State.OperationState.New,
4850
getItem = State.OperationState.New,
51+
deleteItem = State.OperationState.New,
4952
lastInsertedKey = null,
5053
nextSequenceNumber = 19999000,
5154
)
@@ -180,41 +183,84 @@ class MainActivityViewModel(private val app: MyApplication) : ViewModel() {
180183
return true
181184
}
182185

186+
fun deleteItem() {
187+
while (true) {
188+
if (tryDeleteItem()) {
189+
break
190+
}
191+
}
192+
}
193+
194+
private fun tryDeleteItem(): Boolean {
195+
val oldState = _state.value
196+
197+
// If there is no previous successful "insert" operation, then we don't know any ID's to delete,
198+
// so just do nothing.
199+
val key: Zwda6x9zyyKey = oldState.lastInsertedKey ?: return true
200+
201+
// If there is already a "delete" in progress, then just return and let the in-progress
202+
// operation finish.
203+
when (oldState.deleteItem) {
204+
is State.OperationState.InProgress -> return true
205+
is State.OperationState.New,
206+
is State.OperationState.Completed -> Unit
207+
}
208+
209+
// Create a new coroutine to perform the "delete" operation, but don't start it yet by
210+
// specifying start=CoroutineStart.LAZY because we won't start it until the state is
211+
// successfully set.
212+
val newDeleteJob: Deferred<Unit> =
213+
viewModelScope.async(start = CoroutineStart.LAZY) {
214+
app.getConnector().deleteItemByKey.execute(key)
215+
}
216+
217+
// Update the state and start the coroutine if it is successfully set.
218+
val deleteItemOperationInProgressState =
219+
State.OperationState.InProgress(oldState.nextSequenceNumber, key, newDeleteJob)
220+
val newState = oldState.withDeleteInProgress(deleteItemOperationInProgressState)
221+
if (!_state.compareAndSet(oldState, newState)) {
222+
return false
223+
}
224+
225+
// Actually start the coroutine now that the state has been set.
226+
Log.i(TAG, "Deleting item with key: $key")
227+
newState.startDelete(deleteItemOperationInProgressState)
228+
return true
229+
}
230+
183231
@OptIn(ExperimentalCoroutinesApi::class)
184-
private fun State.startGet(
185-
getItemOperationInProgressState:
186-
State.OperationState.InProgress<Zwda6x9zyyKey, GetItemByKeyQuery.Data.Item?>
232+
private fun State.startDelete(
233+
deleteItemOperationInProgressState: State.OperationState.InProgress<Zwda6x9zyyKey, Unit>
187234
) {
188-
require(getItemOperationInProgressState === getItem)
189-
val job: Deferred<GetItemByKeyQuery.Data.Item?> = getItemOperationInProgressState.job
190-
val key: Zwda6x9zyyKey = getItemOperationInProgressState.variables
235+
require(deleteItemOperationInProgressState === deleteItem)
236+
val job: Job = deleteItemOperationInProgressState.job
237+
val key: Zwda6x9zyyKey = deleteItemOperationInProgressState.variables
191238

192239
job.start()
193240

194241
job.invokeOnCompletion { exception ->
195242
val result =
196243
if (exception !== null) {
197-
Log.w(TAG, "WARNING: Getting item with key $key FAILED: $exception", exception)
244+
Log.w(TAG, "WARNING: Deleting item with key $key FAILED: $exception", exception)
198245
Result.failure(exception)
199246
} else {
200-
val item = job.getCompleted()
201-
Log.i(TAG, "Got item with key $key: $item")
202-
Result.success(item)
247+
Log.i(TAG, "Deleted item with key $key")
248+
Result.success(Unit)
203249
}
204250

205251
while (true) {
206252
val oldState = _state.value
207-
if (oldState.getItem !== getItemOperationInProgressState) {
253+
if (oldState.deleteItem !== deleteItemOperationInProgressState) {
208254
break
209255
}
210256

211-
val getItemOperationCompletedState =
257+
val deleteItemOperationCompletedState =
212258
State.OperationState.Completed(
213259
oldState.nextSequenceNumber,
214-
getItemOperationInProgressState.variables,
260+
deleteItemOperationInProgressState.variables,
215261
result,
216262
)
217-
val newState = oldState.withGetCompleted(getItemOperationCompletedState)
263+
val newState = oldState.withDeleteCompleted(deleteItemOperationCompletedState)
218264
if (_state.compareAndSet(oldState, newState)) {
219265
break
220266
}
@@ -226,6 +272,7 @@ class MainActivityViewModel(private val app: MyApplication) : ViewModel() {
226272
class State(
227273
val insertItem: OperationState<InsertItemMutation.Variables, Zwda6x9zyyKey>,
228274
val getItem: OperationState<Zwda6x9zyyKey, GetItemByKeyQuery.Data.Item?>,
275+
val deleteItem: OperationState<Zwda6x9zyyKey, Unit>,
229276
val lastInsertedKey: Zwda6x9zyyKey?,
230277
val nextSequenceNumber: Long,
231278
) {
@@ -236,6 +283,7 @@ class MainActivityViewModel(private val app: MyApplication) : ViewModel() {
236283
State(
237284
insertItem = insertItem,
238285
getItem = getItem,
286+
deleteItem = deleteItem,
239287
lastInsertedKey = lastInsertedKey,
240288
nextSequenceNumber = nextSequenceNumber + 1,
241289
)
@@ -246,6 +294,7 @@ class MainActivityViewModel(private val app: MyApplication) : ViewModel() {
246294
State(
247295
insertItem = insertItem,
248296
getItem = getItem,
297+
deleteItem = deleteItem,
249298
lastInsertedKey = insertItem.result.getOrNull() ?: lastInsertedKey,
250299
nextSequenceNumber = nextSequenceNumber + 1,
251300
)
@@ -256,6 +305,7 @@ class MainActivityViewModel(private val app: MyApplication) : ViewModel() {
256305
State(
257306
insertItem = insertItem,
258307
getItem = getItem,
308+
deleteItem = deleteItem,
259309
lastInsertedKey = lastInsertedKey,
260310
nextSequenceNumber = nextSequenceNumber + 1,
261311
)
@@ -266,6 +316,29 @@ class MainActivityViewModel(private val app: MyApplication) : ViewModel() {
266316
State(
267317
insertItem = insertItem,
268318
getItem = getItem,
319+
deleteItem = deleteItem,
320+
lastInsertedKey = lastInsertedKey,
321+
nextSequenceNumber = nextSequenceNumber + 1,
322+
)
323+
324+
fun withDeleteInProgress(
325+
deleteItem: OperationState.InProgress<Zwda6x9zyyKey, Unit>
326+
): State =
327+
State(
328+
insertItem = insertItem,
329+
getItem = getItem,
330+
deleteItem = deleteItem,
331+
lastInsertedKey = lastInsertedKey,
332+
nextSequenceNumber = nextSequenceNumber + 1,
333+
)
334+
335+
fun withDeleteCompleted(
336+
deleteItem: OperationState.Completed<Zwda6x9zyyKey, Unit>
337+
): State =
338+
State(
339+
insertItem = insertItem,
340+
getItem = getItem,
341+
deleteItem = deleteItem,
269342
lastInsertedKey = lastInsertedKey,
270343
nextSequenceNumber = nextSequenceNumber + 1,
271344
)
@@ -276,13 +349,15 @@ class MainActivityViewModel(private val app: MyApplication) : ViewModel() {
276349
other is State &&
277350
insertItem == other.insertItem &&
278351
getItem == other.getItem &&
352+
deleteItem == other.deleteItem &&
279353
lastInsertedKey == other.lastInsertedKey &&
280354
nextSequenceNumber == other.nextSequenceNumber
281355

282356
override fun toString() =
283357
"State(" +
284358
"insertItem=$insertItem, " +
285359
"getItem=$getItem, " +
360+
"deleteItem=$deleteItem, " +
286361
"lastInsertedKey=$lastInsertedKey, " +
287362
"sequenceNumber=$nextSequenceNumber)"
288363

firebase-dataconnect/demo/src/main/res/layout/activity_main.xml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,22 @@ limitations under the License.
6464
app:layout_constraintRight_toRightOf="parent"
6565
/>
6666

67+
<Button
68+
android:id="@+id/deleteItemButton"
69+
android:layout_width="0dp"
70+
android:layout_height="wrap_content"
71+
android:text="Delete Item"
72+
app:layout_constraintTop_toBottomOf="@id/getItemButton"
73+
app:layout_constraintLeft_toLeftOf="parent"
74+
app:layout_constraintRight_toRightOf="parent"
75+
/>
76+
6777
<TextView
6878
android:id="@+id/progressText"
6979
android:layout_width="0dp"
7080
android:layout_height="wrap_content"
7181
android:layout_margin="8dp"
72-
app:layout_constraintTop_toBottomOf="@id/getItemButton"
82+
app:layout_constraintTop_toBottomOf="@id/deleteItemButton"
7383
app:layout_constraintLeft_toLeftOf="parent"
7484
app:layout_constraintRight_toRightOf="parent"
7585
/>

0 commit comments

Comments
 (0)