Merge branch 'develop' into feature/notif_invit

This commit is contained in:
Benoit Marty 2019-09-23 16:23:22 +02:00 committed by GitHub
commit 546da0f173
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 98 additions and 35 deletions

View file

@ -18,6 +18,7 @@ Bugfix:
- Leaving community (from another client) has no effect on RiotX (#497)
- Push rules was not retrieved after a clear cache
- m.notice messages trigger push notifications (#238)
- Embiggen messages with multiple emojis also for edited messages (#458)
Translations:
-

View file

@ -20,6 +20,7 @@ import android.content.Context
import com.novoda.merlin.Merlin
import com.novoda.merlin.MerlinsBeard
import im.vector.matrix.android.internal.di.MatrixScope
import im.vector.matrix.android.internal.util.BackgroundDetectionObserver
import timber.log.Timber
import java.util.*
import javax.inject.Inject
@ -27,7 +28,9 @@ import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
@MatrixScope
internal class NetworkConnectivityChecker @Inject constructor(context: Context) {
internal class NetworkConnectivityChecker @Inject constructor(context: Context,
backgroundDetectionObserver: BackgroundDetectionObserver)
: BackgroundDetectionObserver.Listener {
private val merlin = Merlin.Builder()
.withConnectableCallbacks()
@ -41,7 +44,12 @@ internal class NetworkConnectivityChecker @Inject constructor(context: Context)
private set
init {
backgroundDetectionObserver.register(this)
}
override fun onMoveToForeground() {
merlin.bind()
merlin.registerDisconnectable {
if (hasInternetAccess) {
Timber.v("On Disconnect")
@ -64,6 +72,10 @@ internal class NetworkConnectivityChecker @Inject constructor(context: Context)
}
}
override fun onMoveToBackground() {
merlin.unbind()
}
suspend fun waitUntilConnected() {
if (hasInternetAccess) {
return

View file

@ -30,7 +30,6 @@ import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.TaskThread
import im.vector.matrix.android.internal.task.configureWith
import im.vector.matrix.android.internal.util.BackgroundDetectionObserver
import kotlinx.coroutines.CancellationException
import timber.log.Timber
import java.net.SocketTimeoutException
import java.util.concurrent.CountDownLatch
@ -140,7 +139,7 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
if (failure is Failure.NetworkConnection && failure.cause is SocketTimeoutException) {
// Timeout are not critical
Timber.v("Timeout")
} else if (failure is Failure.Unknown && failure.throwable is CancellationException) {
} else if (failure is Failure.Cancelled) {
Timber.v("Cancelled")
} else if (failure is Failure.ServerError
&& (failure.error.code == MatrixError.UNKNOWN_TOKEN || failure.error.code == MatrixError.MISSING_TOKEN)) {

View file

@ -27,6 +27,7 @@ import im.vector.riotx.EmojiCompatFontProvider
import im.vector.riotx.EmojiCompatWrapper
import im.vector.riotx.VectorApplication
import im.vector.riotx.core.pushers.PushersManager
import im.vector.riotx.core.utils.DimensionConverter
import im.vector.riotx.features.configuration.VectorConfiguration
import im.vector.riotx.features.crypto.keysrequest.KeyRequestHandler
import im.vector.riotx.features.crypto.verification.IncomingVerificationRequestHandler
@ -63,6 +64,8 @@ interface VectorComponent {
fun resources(): Resources
fun dimensionUtils(): DimensionConverter
fun vectorConfiguration(): VectorConfiguration
fun avatarRenderer(): AvatarRenderer

View file

@ -15,25 +15,26 @@
*/
package im.vector.riotx.core.utils
import android.content.Context
import android.content.res.Resources
import android.util.TypedValue
import javax.inject.Inject
object DimensionUtils {
class DimensionConverter @Inject constructor(val resources: Resources) {
fun dpToPx(dp: Int, context: Context): Int {
fun dpToPx(dp: Int): Int {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dp.toFloat(),
context.resources.displayMetrics
resources.displayMetrics
).toInt()
}
fun spToPx(sp: Int, context: Context): Int {
fun spToPx(sp: Int): Int {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP,
sp.toFloat(),
context.resources.displayMetrics
resources.displayMetrics
).toInt()
}
}

View file

@ -36,7 +36,7 @@ import im.vector.riotx.core.extensions.hideKeyboard
import im.vector.riotx.core.extensions.observeEvent
import im.vector.riotx.core.extensions.setupAsSearch
import im.vector.riotx.core.platform.VectorBaseFragment
import im.vector.riotx.core.utils.DimensionUtils
import im.vector.riotx.core.utils.DimensionConverter
import im.vector.riotx.features.home.AvatarRenderer
import kotlinx.android.synthetic.main.fragment_create_direct_room.*
import javax.inject.Inject
@ -51,6 +51,7 @@ class CreateDirectRoomKnownUsersFragment : VectorBaseFragment(), KnownUsersContr
@Inject lateinit var directRoomController: KnownUsersController
@Inject lateinit var avatarRenderer: AvatarRenderer
@Inject lateinit var dimensionConverter: DimensionConverter
private lateinit var navigationViewModel: CreateDirectRoomNavigationViewModel
override fun injectWith(injector: ScreenComponent) {
@ -156,7 +157,7 @@ class CreateDirectRoomKnownUsersFragment : VectorBaseFragment(), KnownUsersContr
private fun addChipToGroup(user: User, chipGroup: ChipGroup) {
val chip = Chip(requireContext())
chip.setChipBackgroundColorResource(android.R.color.transparent)
chip.chipStrokeWidth = DimensionUtils.dpToPx(1, requireContext()).toFloat()
chip.chipStrokeWidth = dimensionConverter.dpToPx(1).toFloat()
chip.text = if (user.displayName.isNullOrBlank()) user.userId else user.displayName
chip.isClickable = true
chip.isCheckable = false

View file

@ -25,6 +25,7 @@ import im.vector.riotx.core.epoxy.VectorEpoxyModel
import im.vector.riotx.core.resources.ColorProvider
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.core.utils.DebouncedClickListener
import im.vector.riotx.core.utils.DimensionConverter
import im.vector.riotx.features.home.AvatarRenderer
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
import im.vector.riotx.features.home.room.detail.timeline.item.MessageTextItem_
@ -36,7 +37,8 @@ import javax.inject.Inject
class EncryptedItemFactory @Inject constructor(private val messageInformationDataFactory: MessageInformationDataFactory,
private val colorProvider: ColorProvider,
private val stringProvider: StringProvider,
private val avatarRenderer: AvatarRenderer) {
private val avatarRenderer: AvatarRenderer,
private val dimensionConverter: DimensionConverter) {
fun create(event: TimelineEvent,
nextEvent: TimelineEvent?,
@ -69,6 +71,7 @@ class EncryptedItemFactory @Inject constructor(private val messageInformationDat
.message(spannableStr)
.avatarRenderer(avatarRenderer)
.colorProvider(colorProvider)
.dimensionConverter(dimensionConverter)
.informationData(informationData)
.highlighted(highlight)
.avatarCallback(callback)

View file

@ -23,6 +23,7 @@ import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
import im.vector.matrix.android.internal.crypto.model.event.EncryptionEventContent
import im.vector.riotx.R
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.core.utils.DimensionConverter
import im.vector.riotx.features.home.AvatarRenderer
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
import im.vector.riotx.features.home.room.detail.timeline.helper.senderAvatar
@ -33,7 +34,8 @@ import im.vector.riotx.features.home.room.detail.timeline.item.NoticeItem_
import javax.inject.Inject
class EncryptionItemFactory @Inject constructor(private val stringProvider: StringProvider,
private val avatarRenderer: AvatarRenderer) {
private val avatarRenderer: AvatarRenderer,
private val dimensionConverter: DimensionConverter) {
fun create(event: TimelineEvent,
highlight: Boolean,
@ -50,6 +52,7 @@ class EncryptionItemFactory @Inject constructor(private val stringProvider: Stri
)
return NoticeItem_()
.avatarRenderer(avatarRenderer)
.dimensionConverter(dimensionConverter)
.noticeText(text)
.informationData(informationData)
.highlighted(highlight)

View file

@ -19,9 +19,9 @@ package im.vector.riotx.features.home.room.detail.timeline.factory
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.text.TextPaint
import android.text.style.AbsoluteSizeSpan
import android.text.style.ClickableSpan
import android.text.style.ForegroundColorSpan
import android.text.style.RelativeSizeSpan
import android.view.View
import dagger.Lazy
import im.vector.matrix.android.api.permalinks.MatrixLinkify
@ -40,6 +40,8 @@ import im.vector.riotx.core.linkify.VectorLinkify
import im.vector.riotx.core.resources.ColorProvider
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.core.utils.DebouncedClickListener
import im.vector.riotx.core.utils.DimensionConverter
import im.vector.riotx.core.utils.containsOnlyEmojis
import im.vector.riotx.features.home.AvatarRenderer
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
import im.vector.riotx.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder
@ -62,7 +64,8 @@ class MessageItemFactory @Inject constructor(
private val imageContentRenderer: ImageContentRenderer,
private val messageInformationDataFactory: MessageInformationDataFactory,
private val contentUploadStateTrackerBinder: ContentUploadStateTrackerBinder,
private val noticeItemFactory: NoticeItemFactory) {
private val noticeItemFactory: NoticeItemFactory,
private val dimensionConverter: DimensionConverter) {
fun create(event: TimelineEvent,
@ -113,6 +116,7 @@ class MessageItemFactory @Inject constructor(
return MessageFileItem_()
.avatarRenderer(avatarRenderer)
.colorProvider(colorProvider)
.dimensionConverter(dimensionConverter)
.informationData(informationData)
.highlighted(highlight)
.avatarCallback(callback)
@ -142,6 +146,7 @@ class MessageItemFactory @Inject constructor(
return MessageFileItem_()
.avatarRenderer(avatarRenderer)
.colorProvider(colorProvider)
.dimensionConverter(dimensionConverter)
.informationData(informationData)
.highlighted(highlight)
.avatarCallback(callback)
@ -171,6 +176,7 @@ class MessageItemFactory @Inject constructor(
return DefaultItem_()
.text(text)
.avatarRenderer(avatarRenderer)
.dimensionConverter(dimensionConverter)
.highlighted(highlight)
.informationData(informationData)
.baseCallback(callback)
@ -197,6 +203,7 @@ class MessageItemFactory @Inject constructor(
return MessageImageVideoItem_()
.avatarRenderer(avatarRenderer)
.colorProvider(colorProvider)
.dimensionConverter(dimensionConverter)
.imageContentRenderer(imageContentRenderer)
.contentUploadStateTrackerBinder(contentUploadStateTrackerBinder)
.playable(messageContent.info?.mimeType == "image/gif")
@ -251,6 +258,7 @@ class MessageItemFactory @Inject constructor(
.contentUploadStateTrackerBinder(contentUploadStateTrackerBinder)
.avatarRenderer(avatarRenderer)
.colorProvider(colorProvider)
.dimensionConverter(dimensionConverter)
.playable(true)
.informationData(informationData)
.highlighted(highlight)
@ -290,9 +298,11 @@ class MessageItemFactory @Inject constructor(
message(linkifiedBody)
}
}
.useBigFont(linkifiedBody.length <= MAX_NUMBER_OF_EMOJI_FOR_BIG_FONT * 2 && containsOnlyEmojis(linkifiedBody.toString()))
.avatarRenderer(avatarRenderer)
.informationData(informationData)
.colorProvider(colorProvider)
.dimensionConverter(dimensionConverter)
.highlighted(highlight)
.avatarCallback(callback)
.urlClickCallback(callback)
@ -326,7 +336,8 @@ class MessageItemFactory @Inject constructor(
editEnd,
Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
spannable.setSpan(RelativeSizeSpan(.9f), editStart, editEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
// Note: text size is set to 14sp
spannable.setSpan(AbsoluteSizeSpan(dimensionConverter.spToPx(13)), editStart, editEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
spannable.setSpan(object : ClickableSpan() {
override fun onClick(widget: View?) {
callback?.onEditedDecorationClicked(informationData)
@ -359,6 +370,7 @@ class MessageItemFactory @Inject constructor(
.avatarRenderer(avatarRenderer)
.message(message)
.colorProvider(colorProvider)
.dimensionConverter(dimensionConverter)
.informationData(informationData)
.highlighted(highlight)
.avatarCallback(callback)
@ -400,6 +412,7 @@ class MessageItemFactory @Inject constructor(
}
.avatarRenderer(avatarRenderer)
.colorProvider(colorProvider)
.dimensionConverter(dimensionConverter)
.informationData(informationData)
.highlighted(highlight)
.avatarCallback(callback)
@ -423,6 +436,7 @@ class MessageItemFactory @Inject constructor(
return RedactedMessageItem_()
.avatarRenderer(avatarRenderer)
.colorProvider(colorProvider)
.dimensionConverter(dimensionConverter)
.informationData(informationData)
.highlighted(highlight)
.avatarCallback(callback)
@ -447,4 +461,8 @@ class MessageItemFactory @Inject constructor(
VectorLinkify.addLinks(spannable, true)
return spannable
}
companion object {
private const val MAX_NUMBER_OF_EMOJI_FOR_BIG_FONT = 5
}
}

View file

@ -17,12 +17,10 @@
package im.vector.riotx.features.home.room.detail.timeline.factory
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
import im.vector.riotx.core.utils.DimensionConverter
import im.vector.riotx.features.home.AvatarRenderer
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
import im.vector.riotx.features.home.room.detail.timeline.format.NoticeEventFormatter
import im.vector.riotx.features.home.room.detail.timeline.helper.senderAvatar
import im.vector.riotx.features.home.room.detail.timeline.helper.senderName
import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData
import im.vector.riotx.features.home.room.detail.timeline.item.NoticeItem
import im.vector.riotx.features.home.room.detail.timeline.item.NoticeItem_
import im.vector.riotx.features.home.room.detail.timeline.util.MessageInformationDataFactory
@ -30,7 +28,8 @@ import javax.inject.Inject
class NoticeItemFactory @Inject constructor(private val eventFormatter: NoticeEventFormatter,
private val avatarRenderer: AvatarRenderer,
private val informationDataFactory: MessageInformationDataFactory) {
private val informationDataFactory: MessageInformationDataFactory,
private val dimensionConverter: DimensionConverter) {
fun create(event: TimelineEvent,
highlight: Boolean,
@ -40,6 +39,7 @@ class NoticeItemFactory @Inject constructor(private val eventFormatter: NoticeEv
return NoticeItem_()
.avatarRenderer(avatarRenderer)
.dimensionConverter(dimensionConverter)
.noticeText(formattedText)
.highlighted(highlight)
.informationData(informationData)

View file

@ -33,7 +33,6 @@ import im.vector.matrix.android.api.session.room.send.SendState
import im.vector.riotx.R
import im.vector.riotx.core.resources.ColorProvider
import im.vector.riotx.core.utils.DebouncedClickListener
import im.vector.riotx.core.utils.DimensionUtils.dpToPx
import im.vector.riotx.features.home.AvatarRenderer
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
import im.vector.riotx.features.reactions.widget.ReactionButton
@ -100,7 +99,7 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : BaseEventItem<H>() {
super.bind(holder)
if (informationData.showInformation) {
holder.avatarImageView.layoutParams = holder.avatarImageView.layoutParams?.apply {
val size = dpToPx(avatarStyle.avatarSizeDP, holder.view.context)
val size = dimensionConverter.dpToPx(avatarStyle.avatarSizeDP)
height = size
width = size
}

View file

@ -25,7 +25,7 @@ import im.vector.riotx.core.epoxy.VectorEpoxyHolder
import im.vector.riotx.core.epoxy.VectorEpoxyModel
import im.vector.riotx.core.platform.CheckableView
import im.vector.riotx.core.ui.views.ReadReceiptsView
import im.vector.riotx.core.utils.DimensionUtils.dpToPx
import im.vector.riotx.core.utils.DimensionConverter
/**
* Children must override getViewType()
@ -38,10 +38,13 @@ abstract class BaseEventItem<H : BaseEventItem.BaseHolder> : VectorEpoxyModel<H>
@EpoxyAttribute
var highlighted: Boolean = false
@EpoxyAttribute
lateinit var dimensionConverter: DimensionConverter
override fun bind(holder: H) {
super.bind(holder)
//optimize?
val px = dpToPx(avatarStyle.avatarSizeDP + 8, holder.view.context)
val px = dimensionConverter.dpToPx(avatarStyle.avatarSizeDP + 8)
holder.leftGuideline.setGuidelineBegin(px)
holder.checkableBackground.isChecked = highlighted

View file

@ -24,7 +24,6 @@ import androidx.core.widget.TextViewCompat
import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass
import im.vector.riotx.R
import im.vector.riotx.core.utils.containsOnlyEmojis
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
import im.vector.riotx.features.html.PillImageSpan
import kotlinx.coroutines.Dispatchers
@ -39,6 +38,8 @@ abstract class MessageTextItem : AbsMessageItem<MessageTextItem.Holder>() {
@EpoxyAttribute
var message: CharSequence? = null
@EpoxyAttribute
var useBigFont: Boolean = false
@EpoxyAttribute
var urlClickCallback: TimelineEventController.UrlClickCallback? = null
// Better link movement methods fixes the issue when
@ -65,9 +66,7 @@ abstract class MessageTextItem : AbsMessageItem<MessageTextItem.Holder>() {
super.bind(holder)
holder.messageView.movementMethod = mvmtMethod
val msg = message ?: ""
if (msg.length <= 4 && containsOnlyEmojis(msg.toString())) {
if (useBigFont) {
holder.messageView.textSize = 44F
} else {
holder.messageView.textSize = 14F

View file

@ -18,6 +18,7 @@ package im.vector.riotx.features.login
import android.os.Bundle
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.Toast
import androidx.core.view.isVisible
import androidx.transition.TransitionManager
@ -68,12 +69,19 @@ class LoginFragment : VectorBaseFragment() {
homeServerField.focusChanges()
.subscribe {
if (!it) {
// TODO Also when clicking on button?
viewModel.handle(LoginActions.UpdateHomeServer(homeServerField.text.toString()))
}
}
.disposeOnDestroy()
homeServerField.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
viewModel.handle(LoginActions.UpdateHomeServer(homeServerField.text.toString()))
return@setOnEditorActionListener true
}
return@setOnEditorActionListener false
}
val initHsUrl = viewModel.getInitialHomeServerUrl()
if (initHsUrl != null) {
homeServerField.setText(initHsUrl)
@ -170,6 +178,10 @@ class LoginFragment : VectorBaseFragment() {
passwordContainer.isVisible = true
authenticateButton.isVisible = true
authenticateButtonSso.isVisible = false
if (loginField.text.isNullOrBlank() && passwordField.text.isNullOrBlank()) {
//Jump focus to login
loginField.requestFocus()
}
}
LoginMode.Sso -> {
loginField.isVisible = false

View file

@ -137,16 +137,23 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
}
private fun handleUpdateHomeserver(action: LoginActions.UpdateHomeServer) {
currentTask?.cancel()
private fun handleUpdateHomeserver(action: LoginActions.UpdateHomeServer) = withState { state ->
var newConfig : HomeServerConnectionConfig? = null
Try {
val homeServerUri = action.homeServerUrl
homeServerConnectionConfig = HomeServerConnectionConfig.Builder()
newConfig = HomeServerConnectionConfig.Builder()
.withHomeServerUri(homeServerUri)
.build()
}
//Do not retry if we already have flows for this config -> causes infinite focus loop
if (newConfig?.homeServerUri?.toString() == homeServerConnectionConfig?.homeServerUri?.toString()
&& state.asyncHomeServerLoginFlowRequest is Success) return@withState
currentTask?.cancel()
homeServerConnectionConfig = newConfig
val homeServerConnectionConfigFinal = homeServerConnectionConfig
if (homeServerConnectionConfigFinal == null) {

View file

@ -32,13 +32,14 @@ import im.vector.matrix.android.internal.crypto.attachments.ElementToDecrypt
import im.vector.riotx.core.di.ActiveSessionHolder
import im.vector.riotx.core.glide.GlideApp
import im.vector.riotx.core.glide.GlideRequest
import im.vector.riotx.core.utils.DimensionUtils.dpToPx
import im.vector.riotx.core.utils.DimensionConverter
import kotlinx.android.parcel.Parcelize
import timber.log.Timber
import java.io.File
import javax.inject.Inject
class ImageContentRenderer @Inject constructor(private val activeSessionHolder: ActiveSessionHolder) {
class ImageContentRenderer @Inject constructor(private val activeSessionHolder: ActiveSessionHolder,
private val dimensionConverter: DimensionConverter) {
@Parcelize
data class Data(
@ -70,7 +71,7 @@ class ImageContentRenderer @Inject constructor(private val activeSessionHolder:
createGlideRequest(data, mode, imageView, width, height)
.dontAnimate()
.transform(RoundedCorners(dpToPx(8, imageView.context)))
.transform(RoundedCorners(dimensionConverter.dpToPx(8)))
.thumbnail(0.3f)
.into(imageView)

View file

@ -104,6 +104,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textUri"
android:imeOptions="actionDone"
android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout>