Let repository not expose API responses

Signed-off-by: Tim Krüger <t@timkrueger.me>
This commit is contained in:
Tim Krüger 2022-05-10 13:09:45 +02:00
parent bb4102612b
commit 577357011e
No known key found for this signature in database
GPG key ID: FECE3A7222C52A4E
3 changed files with 86 additions and 76 deletions

View file

@ -1,5 +1,6 @@
package com.nextcloud.talk.repositories package com.nextcloud.talk.repositories
import android.util.Log
import autodagger.AutoInjector import autodagger.AutoInjector
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.api.NcApi
@ -7,8 +8,8 @@ import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
import com.nextcloud.talk.models.database.UserEntity import com.nextcloud.talk.models.database.UserEntity
import com.nextcloud.talk.models.json.chat.ChatShareOverall import com.nextcloud.talk.models.json.chat.ChatShareOverall
import com.nextcloud.talk.models.json.chat.ChatShareOverviewOverall
import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.viewmodels.SharedItemsViewModel
import io.reactivex.Observable import io.reactivex.Observable
import retrofit2.Response import retrofit2.Response
import java.util.Locale import java.util.Locale
@ -26,11 +27,11 @@ class SharedItemsRepository {
sharedApplication!!.componentApplication.inject(this) sharedApplication!!.componentApplication.inject(this)
} }
fun media(type: SharedItemType): Observable<Response<ChatShareOverall>>? { fun media(type: SharedItemType): Observable<SharedMediaItems>? {
return media(type, null) return media(type, null)
} }
fun media(type: SharedItemType, lastKnownMessageId: Int?): Observable<Response<ChatShareOverall>>? { fun media(type: SharedItemType, lastKnownMessageId: Int?): Observable<SharedMediaItems>? {
val credentials = ApiUtils.getCredentials(parameters!!.userName, parameters!!.userToken) val credentials = ApiUtils.getCredentials(parameters!!.userName, parameters!!.userToken)
return ncApi.getSharedItems( return ncApi.getSharedItems(
@ -39,24 +40,86 @@ class SharedItemsRepository {
type.toString().lowercase(Locale.ROOT), type.toString().lowercase(Locale.ROOT),
lastKnownMessageId, lastKnownMessageId,
BATCH_SIZE BATCH_SIZE
).map { map(it, type) }
}
private fun map(response: Response<ChatShareOverall>, type: SharedItemType): SharedMediaItems {
var chatLastGiven: Int? = null
val items = mutableMapOf<String, SharedItem>()
if (response.headers()["x-chat-last-given"] != null) {
chatLastGiven = response.headers()["x-chat-last-given"]!!.toInt()
}
val mediaItems = response.body()!!.ocs!!.data
if (mediaItems != null) {
for (it in mediaItems) {
if (it.value.messageParameters?.containsKey("file") == true) {
val fileParameters = it.value.messageParameters!!["file"]!!
val previewAvailable =
"yes".equals(fileParameters["preview-available"]!!, ignoreCase = true)
items[it.value.id] = SharedItem(
fileParameters["id"]!!,
fileParameters["name"]!!,
fileParameters["size"]!!.toLong(),
it.value.timestamp,
fileParameters["path"]!!,
fileParameters["link"]!!,
fileParameters["mimetype"]!!,
previewAvailable,
previewLink(fileParameters["id"]),
parameters!!.userEntity
)
} else {
Log.w(TAG, "location and deckcard are not yet supported")
}
}
}
val sortedMutableItems = items.toSortedMap().values.toList().reversed().toMutableList()
val moreItemsExisting = items.count() == SharedItemsViewModel.BATCH_SIZE
return SharedMediaItems(
type,
sortedMutableItems,
chatLastGiven,
moreItemsExisting,
authHeader()
) )
} }
fun availableTypes(): Observable<Response<ChatShareOverviewOverall>>? { fun availableTypes(): Observable<Set<SharedItemType>> {
val credentials = ApiUtils.getCredentials(parameters!!.userName, parameters!!.userToken) val credentials = ApiUtils.getCredentials(parameters!!.userName, parameters!!.userToken)
return ncApi.getSharedItemsOverview( return ncApi.getSharedItemsOverview(
credentials, credentials,
ApiUtils.getUrlForChatSharedItemsOverview(1, parameters!!.baseUrl, parameters!!.roomToken), ApiUtils.getUrlForChatSharedItemsOverview(1, parameters!!.baseUrl, parameters!!.roomToken),
1 1
) ).map {
val types = mutableSetOf<SharedItemType>()
val typeMap = it.body()!!.ocs!!.data!!
for (t in typeMap) {
if (t.value.isNotEmpty()) {
try {
types += SharedItemType.typeFor(t.key)
} catch (e: IllegalArgumentException) {
Log.w(TAG, "Server responds an unknown shared item type: ${t.key}")
}
}
}
types.toSet()
}
} }
fun authHeader(): Map<String, String> { fun authHeader(): Map<String, String> {
return mapOf(Pair("Authorization", ApiUtils.getCredentials(parameters!!.userName, parameters!!.userToken))) return mapOf(Pair("Authorization", ApiUtils.getCredentials(parameters!!.userName, parameters!!.userToken)))
} }
fun previewLink(fileId: String?): String { private fun previewLink(fileId: String?): String {
return ApiUtils.getUrlForFilePreviewWithFileId( return ApiUtils.getUrlForFilePreviewWithFileId(
parameters!!.baseUrl, parameters!!.baseUrl,
fileId, fileId,
@ -74,5 +137,6 @@ class SharedItemsRepository {
companion object { companion object {
const val BATCH_SIZE: Int = 28 const val BATCH_SIZE: Int = 28
private val TAG = SharedItemsRepository::class.simpleName
} }
} }

View file

@ -2,7 +2,7 @@ package com.nextcloud.talk.repositories
class SharedMediaItems( class SharedMediaItems(
val type: SharedItemType, val type: SharedItemType,
val items: MutableList<SharedItem>, val items: List<SharedItem>,
var lastSeenId: Int?, var lastSeenId: Int?,
var moreItemsExisting: Boolean, var moreItemsExisting: Boolean,
val authHeader: Map<String, String> val authHeader: Map<String, String>

View file

@ -6,9 +6,6 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import com.nextcloud.talk.models.database.UserEntity import com.nextcloud.talk.models.database.UserEntity
import com.nextcloud.talk.models.json.chat.ChatShareOverall
import com.nextcloud.talk.models.json.chat.ChatShareOverviewOverall
import com.nextcloud.talk.repositories.SharedItem
import com.nextcloud.talk.repositories.SharedItemType import com.nextcloud.talk.repositories.SharedItemType
import com.nextcloud.talk.repositories.SharedItemsRepository import com.nextcloud.talk.repositories.SharedItemsRepository
import com.nextcloud.talk.repositories.SharedMediaItems import com.nextcloud.talk.repositories.SharedMediaItems
@ -16,7 +13,6 @@ import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import retrofit2.Response
class SharedItemsViewModel(private val repository: SharedItemsRepository, private val initialType: SharedItemType) : class SharedItemsViewModel(private val repository: SharedItemsRepository, private val initialType: SharedItemType) :
ViewModel() { ViewModel() {
@ -55,46 +51,15 @@ class SharedItemsViewModel(private val repository: SharedItemsRepository, privat
?.subscribe(observer(type, true)) ?.subscribe(observer(type, true))
} }
private fun observer(type: SharedItemType, initModel: Boolean): Observer<Response<ChatShareOverall>> { private fun observer(type: SharedItemType, initModel: Boolean): Observer<SharedMediaItems> {
return object : Observer<Response<ChatShareOverall>> { return object : Observer<SharedMediaItems> {
var chatLastGiven: Int? = null var newSharedItems: SharedMediaItems? = null
val items = mutableMapOf<String, SharedItem>()
override fun onSubscribe(d: Disposable) = Unit override fun onSubscribe(d: Disposable) = Unit
override fun onNext(response: Response<ChatShareOverall>) { override fun onNext(response: SharedMediaItems) {
newSharedItems = response
if (response.headers()["x-chat-last-given"] != null) {
chatLastGiven = response.headers()["x-chat-last-given"]!!.toInt()
}
val mediaItems = response.body()!!.ocs!!.data
if (mediaItems != null) {
for (it in mediaItems) {
if (it.value.messageParameters!!.containsKey("file")) {
val fileParameters = it.value.messageParameters!!["file"]!!
val previewAvailable =
"yes".equals(fileParameters["preview-available"], ignoreCase = true)
items[it.value.id] = SharedItem(
fileParameters["id"]!!,
fileParameters["name"]!!,
fileParameters["size"]?.toLong(),
it.value.timestamp,
fileParameters["path"]!!,
fileParameters["link"],
fileParameters["mimetype"],
previewAvailable,
repository.previewLink(fileParameters["id"]),
repository.parameters!!.userEntity
)
} else {
Log.w(TAG, "location and deckcard are not yet supported")
}
}
}
} }
override fun onError(e: Throwable) { override fun onError(e: Throwable) {
@ -102,27 +67,17 @@ class SharedItemsViewModel(private val repository: SharedItemsRepository, privat
} }
override fun onComplete() { override fun onComplete() {
val sortedMutableItems = items.toSortedMap().values.toList().reversed().toMutableList()
val moreItemsExisting = items.count() == BATCH_SIZE
if (initModel) { if (initModel) {
this@SharedItemsViewModel._sharedItems.value = this@SharedItemsViewModel._sharedItems.value =
SharedMediaItems( newSharedItems
type,
sortedMutableItems,
chatLastGiven,
moreItemsExisting,
repository.authHeader()
)
} else { } else {
val oldItems = this@SharedItemsViewModel._sharedItems.value!!.items val oldItems = this@SharedItemsViewModel._sharedItems.value!!.items
this@SharedItemsViewModel._sharedItems.value = this@SharedItemsViewModel._sharedItems.value =
SharedMediaItems( SharedMediaItems(
type, type,
(oldItems.toMutableList() + sortedMutableItems) as MutableList<SharedItem>, oldItems + newSharedItems!!.items,
chatLastGiven, newSharedItems!!.lastSeenId,
moreItemsExisting, newSharedItems!!.moreItemsExisting,
repository.authHeader() repository.authHeader()
) )
} }
@ -131,25 +86,16 @@ class SharedItemsViewModel(private val repository: SharedItemsRepository, privat
} }
private fun availableTypes() { private fun availableTypes() {
repository.availableTypes()?.subscribeOn(Schedulers.io()) repository.availableTypes().subscribeOn(Schedulers.io())
?.observeOn(AndroidSchedulers.mainThread()) ?.observeOn(AndroidSchedulers.mainThread())
?.subscribe(object : Observer<Response<ChatShareOverviewOverall>> { ?.subscribe(object : Observer<Set<SharedItemType>> {
val types = mutableSetOf<SharedItemType>() var types: Set<SharedItemType>? = null
override fun onSubscribe(d: Disposable) = Unit override fun onSubscribe(d: Disposable) = Unit
override fun onNext(response: Response<ChatShareOverviewOverall>) { override fun onNext(types: Set<SharedItemType>) {
val typeMap = response.body()!!.ocs!!.data!! this.types = types
for (it in typeMap) {
if (it.value.size > 0) {
try {
types += SharedItemType.typeFor(it.key)
} catch (e: IllegalArgumentException) {
Log.w(TAG, "Server responds an unknown shared item type: ${it.key}")
}
}
}
} }
override fun onError(e: Throwable) { override fun onError(e: Throwable) {
@ -157,7 +103,7 @@ class SharedItemsViewModel(private val repository: SharedItemsRepository, privat
} }
override fun onComplete() { override fun onComplete() {
this@SharedItemsViewModel._sharedItemType.value = types this@SharedItemsViewModel._sharedItemType.value = this.types
} }
}) })
} }