Repository: android/nowinandroid
File: core-datastore/src/main/java/com/google/samples/apps/nowinandroid/core/datastore/NiaPreferencesDataSource.kt (Kotlin)

Code before:
     * Adds or removes [value] from the [DslList] provided by [listGetter]
     */
    private suspend fun <T : DslProxy> DataStore<UserPreferences>.editList(
        add: Boolean,
        value: String,
        listGetter: (UserPreferencesKt.Dsl) -> DslList<String, T>,
        clear: UserPreferencesKt.Dsl.(DslList<String, T>) -> Unit,
        addAll: UserPreferencesKt.Dsl.(DslList<String, T>, Iterable<String>) -> Unit
    ) {
        setList(
            listGetter = listGetter,
            listSetter = { currentList ->
                if (add) currentList + value
                else currentList - value
            },
            clear = clear,
            addAll = addAll
        )
    }

    /**
     * Sets the value provided by [listSetter] into the [DslList] read by [listGetter]
     */
    private suspend fun <T : DslProxy> DataStore<UserPreferences>.setList(
        listGetter: (UserPreferencesKt.Dsl) -> DslList<String, T>,
        listSetter: (DslList<String, T>) -> List<String>,
        clear: UserPreferencesKt.Dsl.(DslList<String, T>) -> Unit,
        addAll: UserPreferencesKt.Dsl.(DslList<String, T>, Iterable<String>) -> Unit
    ) {
        try {
            updateData {
                it.copy {
                    val dslList = listGetter(this)
                    val newList = listSetter(dslList)
                    clear(dslList)
                    addAll(dslList, newList)
                }
            }
        } catch (ioException: IOException) {
            Log.e("NiaPreferences", "Failed to update user preferences", ioException)
        }
    }
}


Review comment (refactor):
It seems like there's maybe a little too much abstraction here?

It's a bit confusing that `listSetter` doesn't actually set the list passed to it, but it (may) modify the list it is given, and returns the list that should later be added.

I get why you're doing this though, since the Kotlin bindings that are automatically generated this less than ideal to do.

I think the original way without the `editList`/`setList` helpers was fine, and more straightforward, if a bit verbose.

Maybe we can add a feature request to the protobuf Kotlin bindings to allow exposing these as `MutableList`s?

Code after:
     * Adds or removes [value] from the [DslList] provided by [listGetter]
     */
    private suspend fun <T : DslProxy> DataStore<UserPreferences>.editList(
        add: Boolean,
        value: String,
        listGetter: (UserPreferencesKt.Dsl) -> DslList<String, T>,
        clear: UserPreferencesKt.Dsl.(DslList<String, T>) -> Unit,
        addAll: UserPreferencesKt.Dsl.(DslList<String, T>, Iterable<String>) -> Unit
    ) {
        setList(
            listGetter = listGetter,
            listModifier = { currentList ->
                if (add) currentList + value
                else currentList - value
            },
            clear = clear,
            addAll = addAll
        )
    }

    /**
     * Sets the value provided by [listModifier] into the [DslList] read by [listGetter]
     */
    private suspend fun <T : DslProxy> DataStore<UserPreferences>.setList(
        listGetter: (UserPreferencesKt.Dsl) -> DslList<String, T>,
        listModifier: (DslList<String, T>) -> List<String>,
        clear: UserPreferencesKt.Dsl.(DslList<String, T>) -> Unit,
        addAll: UserPreferencesKt.Dsl.(DslList<String, T>, List<String>) -> Unit
    ) {
        try {
            updateData {
                it.copy {
                    val dslList = listGetter(this)
                    val newList = listModifier(dslList)
                    clear(dslList)
                    addAll(dslList, newList)
                }
            }
        } catch (ioException: IOException) {
            Log.e("NiaPreferences", "Failed to update user preferences", ioException)
        }
    }
}