mirror of
https://github.com/element-hq/element-android
synced 2024-11-24 02:15:35 +03:00
Uploads: add screen - WIP
This commit is contained in:
parent
e9ca876444
commit
88cba74cac
11 changed files with 88 additions and 22 deletions
|
@ -21,6 +21,8 @@ import im.vector.matrix.android.api.session.events.model.Event
|
|||
data class GetUploadsResult(
|
||||
// List of fetched Events, most recent first
|
||||
val events: List<Event>,
|
||||
// token to get more events, or null if there is no more event to fetch
|
||||
val nextToken: String?
|
||||
// token to get more events
|
||||
val nextToken: String,
|
||||
// True if there are more event to load
|
||||
val hasMore: Boolean
|
||||
)
|
||||
|
|
|
@ -23,4 +23,6 @@ internal interface TokenChunkEvent {
|
|||
val end: String?
|
||||
val events: List<Event>
|
||||
val stateEvents: List<Event>
|
||||
|
||||
fun hasMore() = start != end
|
||||
}
|
||||
|
|
|
@ -149,7 +149,7 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy
|
|||
}
|
||||
?: ChunkEntity.create(realm, prevToken, nextToken)
|
||||
|
||||
if (receivedChunk.events.isEmpty() && receivedChunk.end == receivedChunk.start) {
|
||||
if (receivedChunk.events.isEmpty() && !receivedChunk.hasMore()) {
|
||||
handleReachEnd(realm, roomId, direction, currentChunk)
|
||||
} else {
|
||||
handlePagination(realm, roomId, direction, receivedChunk, currentChunk)
|
||||
|
|
|
@ -52,7 +52,8 @@ internal class DefaultGetUploadsTask @Inject constructor(
|
|||
|
||||
return GetUploadsResult(
|
||||
events = chunk.events,
|
||||
nextToken = chunk.end?.takeIf { it != chunk.start }
|
||||
nextToken = chunk.end ?: "",
|
||||
hasMore = chunk.hasMore()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,4 +24,5 @@ sealed class RoomUploadsAction : VectorViewModelAction {
|
|||
data class Share(val event: Event) : RoomUploadsAction()
|
||||
|
||||
object Retry : RoomUploadsAction()
|
||||
object LoadMore : RoomUploadsAction()
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import com.airbnb.mvrx.Fail
|
|||
import com.airbnb.mvrx.FragmentViewModelContext
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
|
@ -35,6 +35,7 @@ import im.vector.matrix.android.api.session.room.uploads.GetUploadsResult
|
|||
import im.vector.matrix.android.internal.util.awaitCallback
|
||||
import im.vector.matrix.rx.rx
|
||||
import im.vector.matrix.rx.unwrap
|
||||
import im.vector.riotx.core.extensions.exhaustive
|
||||
import im.vector.riotx.core.platform.EmptyViewEvents
|
||||
import im.vector.riotx.core.platform.VectorViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -79,6 +80,7 @@ class RoomUploadsViewModel @AssistedInject constructor(
|
|||
|
||||
private fun handleLoadMore() = withState { state ->
|
||||
if (state.asyncEventsRequest is Loading) return@withState
|
||||
if (!state.hasMore) return@withState
|
||||
|
||||
setState {
|
||||
copy(
|
||||
|
@ -100,10 +102,10 @@ class RoomUploadsViewModel @AssistedInject constructor(
|
|||
|
||||
setState {
|
||||
copy(
|
||||
asyncEventsRequest = Uninitialized,
|
||||
asyncEventsRequest = Success(Unit),
|
||||
mediaEvents = this.mediaEvents + groupedEvents[true].orEmpty(),
|
||||
fileEvents = this.fileEvents + groupedEvents[false].orEmpty(),
|
||||
hasMore = result.nextToken != null
|
||||
hasMore = result.hasMore
|
||||
)
|
||||
}
|
||||
} catch (failure: Throwable) {
|
||||
|
@ -120,8 +122,11 @@ class RoomUploadsViewModel @AssistedInject constructor(
|
|||
private var token: String? = null
|
||||
|
||||
override fun handle(action: RoomUploadsAction) {
|
||||
// when (action) {
|
||||
//
|
||||
// }.exhaustive
|
||||
when (action) {
|
||||
is RoomUploadsAction.Download -> TODO()
|
||||
is RoomUploadsAction.Share -> TODO()
|
||||
RoomUploadsAction.Retry -> handleLoadMore()
|
||||
RoomUploadsAction.LoadMore -> handleLoadMore()
|
||||
}.exhaustive
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,9 +30,9 @@ data class RoomUploadsViewState(
|
|||
val mediaEvents: List<Event> = emptyList(),
|
||||
val fileEvents: List<Event> = emptyList(),
|
||||
// Current pagination request
|
||||
val asyncEventsRequest: Async<List<Event>> = Uninitialized,
|
||||
val asyncEventsRequest: Async<Unit> = Uninitialized,
|
||||
// True if more result are available server side
|
||||
val hasMore: Boolean = false
|
||||
val hasMore: Boolean = true
|
||||
) : MvRxState {
|
||||
|
||||
constructor(args: RoomProfileArgs) : this(roomId = args.roomId)
|
||||
|
|
|
@ -18,6 +18,7 @@ package im.vector.riotx.features.roomprofile.uploads.files
|
|||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import com.airbnb.epoxy.EpoxyVisibilityTracker
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
|
@ -41,6 +42,8 @@ class RoomUploadsFilesFragment @Inject constructor(
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val epoxyVisibilityTracker = EpoxyVisibilityTracker()
|
||||
epoxyVisibilityTracker.attach(recyclerView)
|
||||
recyclerView.configureWith(controller, showDivider = true)
|
||||
controller.listener = this
|
||||
}
|
||||
|
@ -59,6 +62,10 @@ class RoomUploadsFilesFragment @Inject constructor(
|
|||
uploadsViewModel.handle(RoomUploadsAction.Retry)
|
||||
}
|
||||
|
||||
override fun loadMore() {
|
||||
uploadsViewModel.handle(RoomUploadsAction.LoadMore)
|
||||
}
|
||||
|
||||
override fun onDownloadClicked(event: Event) {
|
||||
uploadsViewModel.handle(RoomUploadsAction.Download(event))
|
||||
}
|
||||
|
|
|
@ -17,31 +17,33 @@
|
|||
package im.vector.riotx.features.roomprofile.uploads.files
|
||||
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import com.airbnb.epoxy.VisibilityState
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.Success
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.epoxy.errorWithRetryItem
|
||||
import im.vector.riotx.core.epoxy.loadingItem
|
||||
import im.vector.riotx.core.epoxy.noResultItem
|
||||
import im.vector.riotx.core.error.ErrorFormatter
|
||||
import im.vector.riotx.core.resources.ColorProvider
|
||||
import im.vector.riotx.core.resources.StringProvider
|
||||
import im.vector.riotx.features.roomprofile.uploads.RoomUploadsViewState
|
||||
import javax.inject.Inject
|
||||
|
||||
class UploadsFileController @Inject constructor(
|
||||
private val errorFormatter: ErrorFormatter,
|
||||
colorProvider: ColorProvider
|
||||
private val stringProvider: StringProvider
|
||||
) : TypedEpoxyController<RoomUploadsViewState>() {
|
||||
|
||||
interface Listener {
|
||||
fun onRetry()
|
||||
fun loadMore()
|
||||
fun onOpenClicked(event: Event)
|
||||
fun onDownloadClicked(event: Event)
|
||||
fun onShareClicked(event: Event)
|
||||
}
|
||||
|
||||
private val dividerColor = colorProvider.getColorFromAttribute(R.attr.vctr_list_divider_color)
|
||||
|
||||
var listener: Listener? = null
|
||||
|
||||
init {
|
||||
|
@ -65,6 +67,20 @@ class UploadsFileController @Inject constructor(
|
|||
listener { listener?.onRetry() }
|
||||
}
|
||||
}
|
||||
is Success -> {
|
||||
if (data.hasMore) {
|
||||
// We need to load more items
|
||||
listener?.loadMore()
|
||||
loadingItem {
|
||||
id("loading")
|
||||
}
|
||||
} else {
|
||||
noResultItem {
|
||||
id("noResult")
|
||||
text(stringProvider.getString(R.string.uploads_files_no_result))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
buildFileItems(data.fileEvents)
|
||||
|
@ -72,6 +88,11 @@ class UploadsFileController @Inject constructor(
|
|||
if (data.hasMore) {
|
||||
loadingItem {
|
||||
id("loadMore")
|
||||
onVisibilityStateChanged { _, _, visibilityState ->
|
||||
if (visibilityState == VisibilityState.VISIBLE) {
|
||||
listener?.loadMore()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import android.os.Bundle
|
|||
import android.util.DisplayMetrics
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import com.airbnb.epoxy.EpoxyVisibilityTracker
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.riotx.R
|
||||
|
@ -45,6 +46,8 @@ class RoomUploadsMediaFragment @Inject constructor(
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val epoxyVisibilityTracker = EpoxyVisibilityTracker()
|
||||
epoxyVisibilityTracker.attach(recyclerView)
|
||||
recyclerView.layoutManager = GridLayoutManager(context, getNumberOfColumns())
|
||||
recyclerView.adapter = controller.adapter
|
||||
recyclerView.setHasFixedSize(true)
|
||||
|
@ -72,6 +75,10 @@ class RoomUploadsMediaFragment @Inject constructor(
|
|||
navigator.openVideoViewer(requireActivity(), mediaData)
|
||||
}
|
||||
|
||||
override fun loadMore() {
|
||||
uploadsViewModel.handle(RoomUploadsAction.LoadMore)
|
||||
}
|
||||
|
||||
override fun onRetry() {
|
||||
uploadsViewModel.handle(RoomUploadsAction.Retry)
|
||||
}
|
||||
|
|
|
@ -18,22 +18,24 @@ package im.vector.riotx.features.roomprofile.uploads.media
|
|||
|
||||
import android.view.View
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import com.airbnb.epoxy.VisibilityState
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.Success
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.events.model.isImageMessage
|
||||
import im.vector.matrix.android.api.session.events.model.isVideoMessage
|
||||
import im.vector.matrix.android.api.session.events.model.toModel
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageImageContent
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageImageInfoContent
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageVideoContent
|
||||
import im.vector.matrix.android.api.session.room.model.message.getFileUrl
|
||||
import im.vector.matrix.android.internal.crypto.attachments.toElementToDecrypt
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.epoxy.errorWithRetryItem
|
||||
import im.vector.riotx.core.epoxy.noResultItem
|
||||
import im.vector.riotx.core.epoxy.squareLoadingItem
|
||||
import im.vector.riotx.core.error.ErrorFormatter
|
||||
import im.vector.riotx.core.resources.ColorProvider
|
||||
import im.vector.riotx.core.resources.StringProvider
|
||||
import im.vector.riotx.core.utils.DimensionConverter
|
||||
import im.vector.riotx.features.media.ImageContentRenderer
|
||||
import im.vector.riotx.features.media.VideoContentRenderer
|
||||
|
@ -43,18 +45,17 @@ import javax.inject.Inject
|
|||
class UploadsMediaController @Inject constructor(
|
||||
private val errorFormatter: ErrorFormatter,
|
||||
private val imageContentRenderer: ImageContentRenderer,
|
||||
private val dimensionConverter: DimensionConverter,
|
||||
colorProvider: ColorProvider
|
||||
private val stringProvider: StringProvider,
|
||||
dimensionConverter: DimensionConverter
|
||||
) : TypedEpoxyController<RoomUploadsViewState>() {
|
||||
|
||||
interface Listener {
|
||||
fun onRetry()
|
||||
fun onOpenImageClicked(view: View, mediaData: ImageContentRenderer.Data)
|
||||
fun onOpenVideoClicked(view: View, mediaData: VideoContentRenderer.Data)
|
||||
fun loadMore()
|
||||
}
|
||||
|
||||
private val dividerColor = colorProvider.getColorFromAttribute(R.attr.vctr_list_divider_color)
|
||||
|
||||
var listener: Listener? = null
|
||||
|
||||
private val itemSize = dimensionConverter.dpToPx(64)
|
||||
|
@ -80,6 +81,20 @@ class UploadsMediaController @Inject constructor(
|
|||
listener { listener?.onRetry() }
|
||||
}
|
||||
}
|
||||
is Success -> {
|
||||
if (data.hasMore) {
|
||||
// We need to load more items
|
||||
listener?.loadMore()
|
||||
squareLoadingItem {
|
||||
id("loading")
|
||||
}
|
||||
} else {
|
||||
noResultItem {
|
||||
id("noResult")
|
||||
text(stringProvider.getString(R.string.uploads_media_no_result))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
buildMediaItems(data.mediaEvents)
|
||||
|
@ -87,6 +102,11 @@ class UploadsMediaController @Inject constructor(
|
|||
if (data.hasMore) {
|
||||
squareLoadingItem {
|
||||
id("loadMore")
|
||||
onVisibilityStateChanged { _, _, visibilityState ->
|
||||
if (visibilityState == VisibilityState.VISIBLE) {
|
||||
listener?.loadMore()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue