Compare commits

...

5 Commits

Author SHA1 Message Date
b5af62c3ea Some video won't play
VideoView fails to play some remote uri video on some device. For now video is downloaded locally in internal cache then played. This offers basic support before full media preview implementation
2019-08-27 16:50:02 +02:00
a51d96bf00 Merge pull request #325 from vector-im/feature/non_unicode_reaction
Accept non unicode reactions
2019-08-27 08:10:51 -04:00
7e142d201d Use EmojiCompat to build EmojiSpans from text 2019-08-27 11:06:52 +02:00
2be6058971 accept non unicode reactions 2019-08-27 10:58:21 +02:00
49d73f360e Merge pull request #494 from vector-im/feature/fix_441
Fix text diff removed linebreak
2019-08-27 04:36:03 -04:00
14 changed files with 80 additions and 35 deletions

View File

@ -5,15 +5,16 @@ Features:
- Display read receipts in timeline (#81)
Improvements:
-
- Reactions: Reinstate the ability to react with non-unicode keys (#307)
Other changes:
-
-
Bugfix:
- Fix text diff linebreak display (#441)
- Date change message repeats for each redaction until a normal message (#358)
- Slide-in reply icon is distorted (#423)
- Some video won't play
Translations:
-

View File

@ -318,6 +318,8 @@ dependencies {
implementation 'diff_match_patch:diff_match_patch:current'
implementation "androidx.emoji:emoji-appcompat:1.0.0"
// TESTS
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'

View File

@ -19,10 +19,13 @@ package im.vector.riotx
import android.app.Application
import android.content.Context
import android.content.res.Configuration
import android.graphics.Color
import android.os.Handler
import android.os.HandlerThread
import androidx.core.provider.FontRequest
import androidx.core.provider.FontsContractCompat
import androidx.emoji.text.EmojiCompat
import androidx.emoji.text.FontRequestEmojiCompatConfig
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
@ -105,6 +108,23 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.
)
FontsContractCompat.requestFont(this, fontRequest, emojiCompatFontProvider, getFontThreadHandler())
vectorConfiguration.initConfiguration()
//Use emoji compat for the benefit of emoji spans
val config = FontRequestEmojiCompatConfig(this, fontRequest)
.setReplaceAll(true) // we want to replace all emojis with selected font
// .setEmojiSpanIndicatorEnabled(true)
// .setEmojiSpanIndicatorColor(Color.GREEN)
EmojiCompat.init(config)
.registerInitCallback(object : EmojiCompat.InitCallback() {
override fun onInitialized() {
Timber.v("Emoji compat onInitialized success ")
}
override fun onFailed(throwable: Throwable?) {
Timber.e(throwable,"Failed to init EmojiCompat")
}
})
NotificationUtils.createNotificationChannels(applicationContext)
if (authenticator.hasAuthenticatedSessions() && !activeSessionHolder.hasActiveSession()) {
val lastAuthenticatedSession = authenticator.getLastAuthenticatedSession()!!

View File

@ -35,7 +35,6 @@ import im.vector.riotx.R
import im.vector.riotx.core.extensions.canReact
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.core.utils.isSingleEmoji
import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData
@ -244,7 +243,7 @@ class MessageMenuViewModel @AssistedInject constructor(@Assisted initialState: M
//Only event of type Event.EVENT_TYPE_MESSAGE are supported for the moment
if (event.root.getClearType() != EventType.MESSAGE) return false
//TODO if user is admin or moderator
return event.annotations?.reactionsSummary?.any { isSingleEmoji(it.key) } ?: false
return event.annotations?.reactionsSummary?.isNotEmpty() ?: false
}

View File

@ -38,12 +38,8 @@ abstract class ReactionInfoSimpleItem : EpoxyModelWithHolder<ReactionInfoSimpleI
@EpoxyAttribute
var timeStamp: CharSequence? = null
@EpoxyAttribute
var emojiTypeFace: Typeface? = null
override fun bind(holder: Holder) {
holder.emojiReactionView.text = reactionKey
holder.emojiReactionView.typeface = emojiTypeFace ?: Typeface.DEFAULT
holder.displayNameView.text = authorDisplayName
timeStamp?.let {
holder.timeStampView.text = it

View File

@ -28,7 +28,6 @@ import com.airbnb.epoxy.EpoxyRecyclerView
import com.airbnb.mvrx.MvRx
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.riotx.EmojiCompatFontProvider
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData
@ -43,13 +42,12 @@ class ViewReactionBottomSheet : VectorBaseBottomSheetDialogFragment() {
private val viewModel: ViewReactionViewModel by fragmentViewModel(ViewReactionViewModel::class)
@Inject lateinit var viewReactionViewModelFactory: ViewReactionViewModel.Factory
@Inject lateinit var emojiCompatFontProvider: EmojiCompatFontProvider
@BindView(R.id.bottom_sheet_display_reactions_list)
lateinit var epoxyRecyclerView: EpoxyRecyclerView
private val epoxyController by lazy {
ViewReactionsEpoxyController(requireContext(), emojiCompatFontProvider.typeface)
ViewReactionsEpoxyController(requireContext())
}
override fun injectWith(screenComponent: ScreenComponent) {

View File

@ -90,7 +90,7 @@ class ViewReactionViewModel @AssistedInject constructor(@Assisted
.flatMapSingle { summaries ->
Observable
.fromIterable(summaries.reactionsSummary)
.filter { reactionAggregatedSummary -> isSingleEmoji(reactionAggregatedSummary.key) }
//.filter { reactionAggregatedSummary -> isSingleEmoji(reactionAggregatedSummary.key) }
.toReactionInfoList()
}
.execute {

View File

@ -19,6 +19,7 @@ package im.vector.riotx.features.home.room.detail.timeline.action
import android.content.Context
import android.graphics.Typeface
import android.text.format.DateUtils
import androidx.emoji.text.EmojiCompat
import com.airbnb.epoxy.TypedEpoxyController
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Incomplete
@ -30,7 +31,7 @@ import im.vector.riotx.core.ui.list.genericLoaderItem
/**
* Epoxy controller for reaction event list
*/
class ViewReactionsEpoxyController(private val context: Context, private val emojiCompatTypeface: Typeface?)
class ViewReactionsEpoxyController(private val context: Context)
: TypedEpoxyController<DisplayReactionsViewState>() {
override fun buildModels(state: DisplayReactionsViewState) {
@ -50,9 +51,8 @@ class ViewReactionsEpoxyController(private val context: Context, private val emo
state.mapReactionKeyToMemberList()?.forEach {
reactionInfoSimpleItem {
id(it.eventId)
emojiTypeFace(emojiCompatTypeface)
timeStamp(it.timestamp)
reactionKey(it.reactionKey)
reactionKey(EmojiCompat.get().process(it.reactionKey))
authorDisplayName(it.authorName ?: it.authorId)
}
}

View File

@ -151,7 +151,7 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : BaseEventItem<H>() {
idToRefInFlow.add(reactionButton.id)
reactionButton.reactionString = reaction.key
reactionButton.reactionCount = reaction.count
reactionButton.emojiTypeFace = emojiTypeFace
//reactionButton.emojiTypeFace = emojiTypeFace
reactionButton.setChecked(reaction.addedByMe)
reactionButton.isEnabled = reaction.synced
}

View File

@ -71,7 +71,7 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses
memberName = formattedMemberName,
showInformation = showInformation,
orderedReactionList = event.annotations?.reactionsSummary
?.filter { isSingleEmoji(it.key) }
//?.filter { isSingleEmoji(it.key) }
?.map {
ReactionInfoData(it.key, it.count, it.addedByMe, it.localEchoEvents.isEmpty())
},

View File

@ -89,18 +89,44 @@ class VideoContentRenderer @Inject constructor(private val activeSessionHolder:
})
}
} else {
thumbnailView.isVisible = false
loadingView.isVisible = false
val resolvedUrl = contentUrlResolver.resolveFullSize(data.url)
if (resolvedUrl == null) {
thumbnailView.isVisible = false
loadingView.isVisible = false
errorView.isVisible = true
errorView.setText(R.string.unknown_error)
} else {
videoView.isVisible = true
videoView.setVideoPath(resolvedUrl)
videoView.start()
//Temporary code, some remote videos are not played by videoview setVideoUri
//So for now we download them then play
thumbnailView.isVisible = true
loadingView.isVisible = true
activeSessionHolder.getActiveSession()
.downloadFile(
FileService.DownloadMode.FOR_INTERNAL_USE,
data.eventId,
data.filename,
data.url,
null,
object : MatrixCallback<File> {
override fun onSuccess(data: File) {
thumbnailView.isVisible = false
loadingView.isVisible = false
videoView.isVisible = true
videoView.setVideoPath(data.path)
videoView.start()
}
override fun onFailure(failure: Throwable) {
loadingView.isVisible = false
errorView.isVisible = true
errorView.text = errorFormatter.toHumanReadable(failure)
}
})
}
}
}

View File

@ -35,6 +35,7 @@ import android.widget.TextView
import androidx.annotation.ColorInt
import androidx.annotation.ColorRes
import androidx.core.content.ContextCompat
import androidx.emoji.text.EmojiCompat
import im.vector.riotx.R
import im.vector.riotx.core.utils.TextUtils
@ -58,12 +59,6 @@ class ReactionButton @JvmOverloads constructor(context: Context, attrs: Attribut
private var reactionSelector: View? = null
var emojiTypeFace: Typeface? = null
set(value) {
field = value
emojiView?.typeface = value ?: Typeface.DEFAULT
}
private var dotsView: DotsView
private var circleView: CircleView
var reactedListener: ReactedListener? = null
@ -82,7 +77,9 @@ class ReactionButton @JvmOverloads constructor(context: Context, attrs: Attribut
var reactionString = "😀"
set(value) {
field = value
emojiView?.text = field
//maybe cache this for performances?
val emojiSpanned = EmojiCompat.get().process(value)
emojiView?.text = emojiSpanned
}
private var animationScaleFactor: Float = 0.toFloat()
@ -104,7 +101,7 @@ class ReactionButton @JvmOverloads constructor(context: Context, attrs: Attribut
countTextView?.text = TextUtils.formatCountToShortDecimal(reactionCount)
emojiView?.typeface = this.emojiTypeFace ?: Typeface.DEFAULT
// emojiView?.typeface = this.emojiTypeFace ?: Typeface.DEFAULT
val array = context.obtainStyledAttributes(attrs, R.styleable.ReactionButton, defStyleAttr, 0)

View File

@ -34,7 +34,9 @@
android:id="@+id/videoMediaViewerThumbnailView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:visibility="gone"
android:scaleType="centerInside"
tools:visibility="visible" />
<ProgressBar
@ -49,6 +51,7 @@
android:id="@+id/videoMediaViewerVideoView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:visibility="gone" />
<TextView

View File

@ -37,20 +37,23 @@
<TextView
android:id="@+id/reactionText"
android:layout_width="20dp"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:layout_gravity="center"
android:minWidth="20dp"
android:layout_marginStart="6dp"
android:layout_marginLeft="6dp"
android:gravity="center"
android:textColor="@color/black"
android:textSize="13sp"
android:maxEms="10"
android:ellipsize="middle"
android:singleLine="true"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toStartOf="@id/reactionCount"
tools:text="👍" />
tools:text="* Party Parrot Again * 👀" />
<TextView
android:id="@+id/reactionCount"
@ -58,8 +61,8 @@
android:layout_height="wrap_content"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintBaseline_toBaselineOf="@id/reactionText"
android:layout_marginStart="-4dp"
android:layout_marginLeft="-4dp"
android:layout_marginStart="2dp"
android:layout_marginLeft="2dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:gravity="center"