Merge branch 'develop' into feature/ui_test

This commit is contained in:
Benoit Marty 2020-09-29 16:13:44 +02:00 committed by GitHub
commit 487bbe42a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 122 additions and 13 deletions

View File

@ -6,6 +6,7 @@ Features ✨:
Improvements 🙌: Improvements 🙌:
- PIN code: request PIN code if phone has been locked - PIN code: request PIN code if phone has been locked
- Small optimisation of scrolling experience in timeline (#2114)
Bugfix 🐛: Bugfix 🐛:
- Fix Splash layout on small screens - Fix Splash layout on small screens
@ -21,6 +22,7 @@ Build 🧱:
Other changes: Other changes:
- Added registration/verification automated UI tests - Added registration/verification automated UI tests
- Create a script to help getting public information form any homeserver
Changes in Element 1.0.8 (2020-09-25) Changes in Element 1.0.8 (2020-09-25)
=================================================== ===================================================

69
tools/hs_diag.py Executable file
View File

@ -0,0 +1,69 @@
#!/usr/bin/env python3
# Copyright (c) 2020 New Vector Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
import os
### Arguments
parser = argparse.ArgumentParser(description='Get some information about a homeserver.')
parser.add_argument('-s',
'--homeserver',
required=True,
help="homeserver URL")
parser.add_argument('-v',
'--verbose',
help="increase output verbosity.",
action="store_true")
args = parser.parse_args()
if args.verbose:
print("Argument:")
print(args)
baseUrl = args.homeserver
if not baseUrl.startswith("http"):
baseUrl = "https://" + baseUrl
if not baseUrl.endswith("/"):
baseUrl = baseUrl + "/"
print("Get information from " + baseUrl)
items = [
# [Title, URL, True for GET request and False for POST request]
["Well-known", baseUrl + ".well-known/matrix/client", True]
, ["Version", baseUrl + "_matrix/client/versions", True]
, ["Login flow", baseUrl + "_matrix/client/r0/login", True]
, ["Registration flow", baseUrl + "_matrix/client/r0/register", False]
# Useless , ["Username availability", baseUrl + "_matrix/client/r0/register/available?username=benoit", True]
# Useless , ["Public rooms", baseUrl + "_matrix/client/r0/publicRooms?limit=1", True]
# Useless , ["Profile", baseUrl + "_matrix/client/r0/profile/@benoit.marty:matrix.org", True]
# Need token , ["Capability", baseUrl + "_matrix/client/r0/capabilities", True]
# Need token , ["Media config", baseUrl + "_matrix/media/r0/config", True]
# Need token , ["Turn", baseUrl + "_matrix/client/r0/voip/turnServer", True]
]
for item in items:
print("====================================================================================================")
print("# " + item[0] + " (" + item[1] + ")")
print("====================================================================================================")
if item[2]:
os.system("curl -s -X GET '" + item[1] + "' | python -m json.tool")
else:
os.system("curl -s -X POST --data $'{}' '" + item[1] + "' | python -m json.tool")

View File

@ -344,6 +344,7 @@ dependencies {
implementation 'com.jakewharton.rxbinding3:rxbinding-material:3.0.0' implementation 'com.jakewharton.rxbinding3:rxbinding-material:3.0.0'
implementation("com.airbnb.android:epoxy:$epoxy_version") implementation("com.airbnb.android:epoxy:$epoxy_version")
implementation "com.airbnb.android:epoxy-glide-preloading:$epoxy_version"
kapt "com.airbnb.android:epoxy-processor:$epoxy_version" kapt "com.airbnb.android:epoxy-processor:$epoxy_version"
implementation "com.airbnb.android:epoxy-paging:$epoxy_version" implementation "com.airbnb.android:epoxy-paging:$epoxy_version"
implementation 'com.airbnb.android:mvrx:1.3.0' implementation 'com.airbnb.android:mvrx:1.3.0'

View File

@ -53,6 +53,8 @@ import androidx.recyclerview.widget.RecyclerView
import butterknife.BindView import butterknife.BindView
import com.airbnb.epoxy.EpoxyModel import com.airbnb.epoxy.EpoxyModel
import com.airbnb.epoxy.OnModelBuildFinishedListener import com.airbnb.epoxy.OnModelBuildFinishedListener
import com.airbnb.epoxy.addGlidePreloader
import com.airbnb.epoxy.glidePreloader
import com.airbnb.mvrx.Async import com.airbnb.mvrx.Async
import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Loading import com.airbnb.mvrx.Loading
@ -75,6 +77,7 @@ import im.vector.app.core.extensions.setTextOrHide
import im.vector.app.core.extensions.showKeyboard import im.vector.app.core.extensions.showKeyboard
import im.vector.app.core.extensions.trackItemsVisibilityChange import im.vector.app.core.extensions.trackItemsVisibilityChange
import im.vector.app.core.glide.GlideApp import im.vector.app.core.glide.GlideApp
import im.vector.app.core.glide.GlideRequests
import im.vector.app.core.intent.getMimeTypeFromUri import im.vector.app.core.intent.getMimeTypeFromUri
import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.resources.ColorProvider import im.vector.app.core.resources.ColorProvider
@ -218,7 +221,8 @@ class RoomDetailFragment @Inject constructor(
private val colorProvider: ColorProvider, private val colorProvider: ColorProvider,
private val notificationUtils: NotificationUtils, private val notificationUtils: NotificationUtils,
private val webRtcPeerConnectionManager: WebRtcPeerConnectionManager, private val webRtcPeerConnectionManager: WebRtcPeerConnectionManager,
private val matrixItemColorProvider: MatrixItemColorProvider private val matrixItemColorProvider: MatrixItemColorProvider,
private val imageContentRenderer: ImageContentRenderer
) : ) :
VectorBaseFragment(), VectorBaseFragment(),
TimelineEventController.Callback, TimelineEventController.Callback,
@ -921,6 +925,16 @@ class RoomDetailFragment @Inject constructor(
val touchHelper = ItemTouchHelper(swipeCallback) val touchHelper = ItemTouchHelper(swipeCallback)
touchHelper.attachToRecyclerView(recyclerView) touchHelper.attachToRecyclerView(recyclerView)
} }
recyclerView.addGlidePreloader(
epoxyController = timelineEventController,
requestManager = GlideApp.with(this),
preloader = glidePreloader { requestManager, epoxyModel: MessageImageVideoItem, _ ->
imageContentRenderer.createGlideRequest(
epoxyModel.mediaData,
ImageContentRenderer.Mode.THUMBNAIL,
requestManager as GlideRequests
)
})
} }
private fun updateJumpToReadMarkerViewVisibility() { private fun updateJumpToReadMarkerViewVisibility() {

View File

@ -56,6 +56,8 @@ import org.matrix.android.sdk.api.session.room.timeline.Timeline
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
import javax.inject.Inject import javax.inject.Inject
private const val DEFAULT_PREFETCH_THRESHOLD = 30
class TimelineEventController @Inject constructor(private val dateFormatter: VectorDateFormatter, class TimelineEventController @Inject constructor(private val dateFormatter: VectorDateFormatter,
private val contentUploadStateTrackerBinder: ContentUploadStateTrackerBinder, private val contentUploadStateTrackerBinder: ContentUploadStateTrackerBinder,
private val contentDownloadStateTrackerBinder: ContentDownloadStateTrackerBinder, private val contentDownloadStateTrackerBinder: ContentDownloadStateTrackerBinder,
@ -116,6 +118,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
private var unreadState: UnreadState = UnreadState.Unknown private var unreadState: UnreadState = UnreadState.Unknown
private var positionOfReadMarker: Int? = null private var positionOfReadMarker: Int? = null
private var eventIdToHighlight: String? = null private var eventIdToHighlight: String? = null
private var previousModelsSize = 0
var callback: Callback? = null var callback: Callback? = null
var timeline: Timeline? = null var timeline: Timeline? = null
@ -191,6 +194,29 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
models.add(position, readMarker) models.add(position, readMarker)
} }
} }
val shouldAddBackwardPrefetch = timeline?.hasMoreToLoad(Timeline.Direction.BACKWARDS) ?: false
if (shouldAddBackwardPrefetch) {
val indexOfPrefetchBackward = (previousModelsSize - 1)
.coerceAtMost(models.size - DEFAULT_PREFETCH_THRESHOLD)
.coerceAtLeast(0)
val loadingItem = LoadingItem_()
.id("prefetch_backward_loading${System.currentTimeMillis()}")
.showLoader(false)
.setVisibilityStateChangedListener(Timeline.Direction.BACKWARDS)
models.add(indexOfPrefetchBackward, loadingItem)
}
val shouldAddForwardPrefetch = timeline?.hasMoreToLoad(Timeline.Direction.FORWARDS) ?: false
if (shouldAddForwardPrefetch) {
val indexOfPrefetchForward = DEFAULT_PREFETCH_THRESHOLD.coerceAtMost(models.size - 1)
val loadingItem = LoadingItem_()
.id("prefetch_forward_loading${System.currentTimeMillis()}")
.showLoader(false)
.setVisibilityStateChangedListener(Timeline.Direction.FORWARDS)
models.add(indexOfPrefetchForward, loadingItem)
}
previousModelsSize = models.size
} }
fun update(viewState: RoomDetailViewState) { fun update(viewState: RoomDetailViewState) {
@ -355,9 +381,6 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
return shouldAdd return shouldAdd
} }
/**
* Return true if added
*/
private fun LoadingItem_.setVisibilityStateChangedListener(direction: Timeline.Direction): LoadingItem_ { private fun LoadingItem_.setVisibilityStateChangedListener(direction: Timeline.Direction): LoadingItem_ {
return onVisibilityStateChanged { _, _, visibilityState -> return onVisibilityStateChanged { _, _, visibilityState ->
if (visibilityState == VisibilityState.VISIBLE) { if (visibilityState == VisibilityState.VISIBLE) {

View File

@ -33,6 +33,7 @@ import im.vector.app.R
import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.glide.GlideApp import im.vector.app.core.glide.GlideApp
import im.vector.app.core.glide.GlideRequest import im.vector.app.core.glide.GlideRequest
import im.vector.app.core.glide.GlideRequests
import im.vector.app.core.ui.model.Size import im.vector.app.core.ui.model.Size
import im.vector.app.core.utils.DimensionConverter import im.vector.app.core.utils.DimensionConverter
import im.vector.app.core.utils.isLocalFile import im.vector.app.core.utils.isLocalFile
@ -206,12 +207,14 @@ class ImageContentRenderer @Inject constructor(private val activeSessionHolder:
.into(imageView) .into(imageView)
} }
private fun createGlideRequest(data: Data, mode: Mode, imageView: ImageView, size: Size): GlideRequest<Drawable> { fun createGlideRequest(data: Data, mode: Mode, imageView: ImageView, size: Size): GlideRequest<Drawable> {
return createGlideRequest(data, mode, GlideApp.with(imageView), size)
}
fun createGlideRequest(data: Data, mode: Mode, glideRequests: GlideRequests, size: Size = processSize(data, mode)): GlideRequest<Drawable> {
return if (data.elementToDecrypt != null) { return if (data.elementToDecrypt != null) {
// Encrypted image // Encrypted image
GlideApp glideRequests.load(data)
.with(imageView)
.load(data)
} else { } else {
// Clear image // Clear image
val contentUrlResolver = activeSessionHolder.getActiveSession().contentUrlResolver() val contentUrlResolver = activeSessionHolder.getActiveSession().contentUrlResolver()
@ -223,15 +226,12 @@ class ImageContentRenderer @Inject constructor(private val activeSessionHolder:
// Fallback to base url // Fallback to base url
?: data.url.takeIf { it?.startsWith("content://") == true } ?: data.url.takeIf { it?.startsWith("content://") == true }
GlideApp glideRequests
.with(imageView)
.load(resolvedUrl) .load(resolvedUrl)
.apply { .apply {
if (mode == Mode.THUMBNAIL) { if (mode == Mode.THUMBNAIL) {
error( error(
GlideApp glideRequests.load(resolveUrl(data))
.with(imageView)
.load(resolveUrl(data))
) )
} }
} }