|
|
|
@ -18,55 +18,69 @@ package com.google.samples.apps.nowinandroid.core.datastore
|
|
|
|
|
|
|
|
|
|
import android.util.Log
|
|
|
|
|
import androidx.datastore.core.DataStore
|
|
|
|
|
import com.google.protobuf.kotlin.DslList
|
|
|
|
|
import com.google.protobuf.kotlin.DslProxy
|
|
|
|
|
import com.google.samples.apps.nowinandroid.core.model.data.UserData
|
|
|
|
|
import java.io.IOException
|
|
|
|
|
import javax.inject.Inject
|
|
|
|
|
import kotlinx.coroutines.flow.Flow
|
|
|
|
|
import kotlinx.coroutines.flow.firstOrNull
|
|
|
|
|
import kotlinx.coroutines.flow.map
|
|
|
|
|
import kotlinx.coroutines.flow.retry
|
|
|
|
|
|
|
|
|
|
class NiaPreferencesDataSource @Inject constructor(
|
|
|
|
|
private val userPreferences: DataStore<UserPreferences>
|
|
|
|
|
) {
|
|
|
|
|
suspend fun setFollowedTopicIds(followedTopicIds: Set<String>) {
|
|
|
|
|
try {
|
|
|
|
|
userPreferences.updateData {
|
|
|
|
|
it.copy {
|
|
|
|
|
this.followedTopicIds.clear()
|
|
|
|
|
this.followedTopicIds.addAll(followedTopicIds)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (ioException: IOException) {
|
|
|
|
|
Log.e("NiaPreferences", "Failed to update user preferences", ioException)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
suspend fun toggleFollowedTopicId(followedTopicId: String, followed: Boolean) {
|
|
|
|
|
try {
|
|
|
|
|
userPreferences.updateData {
|
|
|
|
|
it.copy {
|
|
|
|
|
val current =
|
|
|
|
|
if (followed) {
|
|
|
|
|
followedTopicIds + followedTopicId
|
|
|
|
|
} else {
|
|
|
|
|
followedTopicIds - followedTopicId
|
|
|
|
|
}
|
|
|
|
|
this.followedTopicIds.clear()
|
|
|
|
|
this.followedTopicIds.addAll(current)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (ioException: IOException) {
|
|
|
|
|
Log.e("NiaPreferences", "Failed to update user preferences", ioException)
|
|
|
|
|
}
|
|
|
|
|
val userDataStream = userPreferences.data
|
|
|
|
|
.map {
|
|
|
|
|
UserData(
|
|
|
|
|
bookmarkedNewsResources = it.bookmarkedNewsResourceIdsList.toSet(),
|
|
|
|
|
followedTopics = it.followedTopicIdsList.toSet(),
|
|
|
|
|
followedAuthors = it.followedAuthorIdsList.toSet(),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val followedTopicIds: Flow<Set<String>> = userPreferences.data
|
|
|
|
|
.retry {
|
|
|
|
|
Log.e("NiaPreferences", "Failed to read user preferences", it)
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
.map { it.followedTopicIdsList.toSet() }
|
|
|
|
|
suspend fun setFollowedTopicIds(followedTopicIds: Set<String>) =
|
|
|
|
|
userPreferences.setList(
|
|
|
|
|
listGetter = { it.followedTopicIds },
|
|
|
|
|
listModifier = { followedTopicIds.toList() },
|
|
|
|
|
clear = { it.clear() },
|
|
|
|
|
addAll = { dslList, editedList -> dslList.addAll(editedList) }
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
suspend fun toggleFollowedTopicId(followedTopicId: String, followed: Boolean) =
|
|
|
|
|
userPreferences.editList(
|
|
|
|
|
add = followed,
|
|
|
|
|
value = followedTopicId,
|
|
|
|
|
listGetter = { it.followedTopicIds },
|
|
|
|
|
clear = { it.clear() },
|
|
|
|
|
addAll = { dslList, editedList -> dslList.addAll(editedList) }
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
suspend fun setFollowedAuthorIds(followedAuthorIds: Set<String>) =
|
|
|
|
|
userPreferences.setList(
|
|
|
|
|
listGetter = { it.followedAuthorIds },
|
|
|
|
|
listModifier = { followedAuthorIds.toList() },
|
|
|
|
|
clear = { it.clear() },
|
|
|
|
|
addAll = { dslList, editedList -> dslList.addAll(editedList) }
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
suspend fun toggleFollowedAuthorId(followedAuthorId: String, followed: Boolean) =
|
|
|
|
|
userPreferences.editList(
|
|
|
|
|
add = followed,
|
|
|
|
|
value = followedAuthorId,
|
|
|
|
|
listGetter = { it.followedAuthorIds },
|
|
|
|
|
clear = { it.clear() },
|
|
|
|
|
addAll = { dslList, editedList -> dslList.addAll(editedList) }
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
suspend fun toggleNewsResourceBookmark(newsResourceId: String, bookmarked: Boolean) =
|
|
|
|
|
userPreferences.editList(
|
|
|
|
|
add = bookmarked,
|
|
|
|
|
value = newsResourceId,
|
|
|
|
|
listGetter = { it.bookmarkedNewsResourceIds },
|
|
|
|
|
clear = { it.clear() },
|
|
|
|
|
addAll = { dslList, editedList -> dslList.addAll(editedList) }
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
suspend fun getChangeListVersions() = userPreferences.data
|
|
|
|
|
.map {
|
|
|
|
@ -106,51 +120,47 @@ class NiaPreferencesDataSource @Inject constructor(
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
suspend fun setFollowedAuthorIds(followedAuthorIds: Set<String>) {
|
|
|
|
|
try {
|
|
|
|
|
userPreferences.updateData {
|
|
|
|
|
it.copy {
|
|
|
|
|
this.followedAuthorIds.clear()
|
|
|
|
|
this.followedAuthorIds.addAll(followedAuthorIds)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (ioException: IOException) {
|
|
|
|
|
Log.e("NiaPreferences", "Failed to update user preferences", ioException)
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* 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
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
suspend fun toggleFollowedAuthorId(followedAuthorId: String, followed: Boolean) {
|
|
|
|
|
/**
|
|
|
|
|
* 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 {
|
|
|
|
|
userPreferences.updateData {
|
|
|
|
|
updateData {
|
|
|
|
|
it.copy {
|
|
|
|
|
val current =
|
|
|
|
|
if (followed) {
|
|
|
|
|
followedAuthorIds + followedAuthorId
|
|
|
|
|
} else {
|
|
|
|
|
followedAuthorIds - followedAuthorId
|
|
|
|
|
}
|
|
|
|
|
this.followedAuthorIds.clear()
|
|
|
|
|
this.followedAuthorIds.addAll(current)
|
|
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val followedAuthorIds: Flow<Set<String>> = userPreferences.data
|
|
|
|
|
.retry {
|
|
|
|
|
Log.e("NiaPreferences", "Failed to read user preferences", it)
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
.map { it.followedAuthorIdsList.toSet() }
|
|
|
|
|
|
|
|
|
|
val userDataStream = userPreferences.data
|
|
|
|
|
.map {
|
|
|
|
|
UserData(
|
|
|
|
|
bookmarkedNewsResources = emptySet(),
|
|
|
|
|
followedTopics = it.followedTopicIdsList.toSet(),
|
|
|
|
|
followedAuthors = it.followedAuthorIdsList.toSet(),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|