Merge branch 'develop' into feature/stabilization

This commit is contained in:
ganfra 2020-01-08 22:28:08 +01:00
commit 8c4d8763a2
12 changed files with 164 additions and 41 deletions

View file

@ -12,14 +12,18 @@ Improvements 🙌:
- Improve devices list screen
- Add settings for rageshake sensibility
- Fix autocompletion issues and add support for rooms, groups, and emoji (#780)
- Show skip to bottom FAB while scrolling down (#752)
Other changes:
- Change the way RiotX identifies a session to allow the SDK to support several sessions with the same user (#800)
- Exclude play-services-oss-licenses library from F-Droid build (#814)
Bugfix 🐛:
- Fix crash when opening room creation screen from the room filtering screen
- Fix avatar image disappearing (#777)
- Fix read marker banner when permalink
- Fix joining upgraded rooms (#697)
- Fix matrix.org room directory not being browsable (#807)
- Hide non working settings (#751)
Translations 🗣:

View file

@ -212,11 +212,12 @@ internal interface RoomAPI {
/**
* Join the given room.
*
* @param roomId the room id
* @param roomIdOrAlias the room id or alias
* @param server_name the servers to attempt to join the room through
* @param params the request body
*/
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/join")
fun join(@Path("roomId") roomId: String,
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "join/{roomIdOrAlias}")
fun join(@Path("roomIdOrAlias") roomIdOrAlias: String,
@Query("server_name") viaServers: List<String>,
@Body params: Map<String, String?>): Call<Unit>

View file

@ -186,6 +186,7 @@ android {
gplay {
dimension "store"
resValue "bool", "isGplay", "true"
buildConfigField "boolean", "ALLOW_FCM_USE", "true"
buildConfigField "String", "SHORT_FLAVOR_DESCRIPTION", "\"G\""
buildConfigField "String", "FLAVOR_DESCRIPTION", "\"GooglePlay\""
@ -194,6 +195,7 @@ android {
fdroid {
dimension "store"
resValue "bool", "isGplay", "false"
buildConfigField "boolean", "ALLOW_FCM_USE", "false"
buildConfigField "String", "SHORT_FLAVOR_DESCRIPTION", "\"F\""
buildConfigField "String", "FLAVOR_DESCRIPTION", "\"FDroid\""
@ -249,9 +251,6 @@ dependencies {
implementation "com.squareup.moshi:moshi-adapters:$moshi_version"
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version"
// OSS License
implementation 'com.google.android.gms:play-services-oss-licenses:17.0.0'
// Log
implementation 'com.jakewharton.timber:timber:4.7.1'
@ -343,6 +342,9 @@ dependencies {
exclude group: 'com.google.firebase', module: 'firebase-measurement-connector'
}
// OSS License, gplay flavor only
gplayImplementation 'com.google.android.gms:play-services-oss-licenses:17.0.0'
implementation "androidx.emoji:emoji-appcompat:1.0.0"
// TESTS

View file

@ -0,0 +1,22 @@
/*
* Copyright 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.
*/
package im.vector.riotx
import android.content.Context
// No op
fun openOssLicensesMenuActivity(@Suppress("UNUSED_PARAMETER") context: Context) = Unit

View file

@ -0,0 +1,23 @@
/*
* Copyright 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.
*/
package im.vector.riotx
import android.content.Context
import android.content.Intent
import com.google.android.gms.oss.licenses.OssLicensesMenuActivity
fun openOssLicensesMenuActivity(context: Context) = context.startActivity(Intent(context, OssLicensesMenuActivity::class.java))

View file

@ -19,16 +19,14 @@ package im.vector.riotx.core.utils
import android.os.Handler
internal class Debouncer(private val handler: Handler) {
class Debouncer(private val handler: Handler) {
private val runnables = HashMap<String, Runnable>()
fun debounce(identifier: String, millis: Long, r: Runnable): Boolean {
if (runnables.containsKey(identifier)) {
// debounce
val old = runnables[identifier]
handler.removeCallbacks(old)
}
// debounce
cancel(identifier)
insertRunnable(identifier, r, millis)
return true
}
@ -37,6 +35,14 @@ internal class Debouncer(private val handler: Handler) {
handler.removeCallbacksAndMessages(null)
}
fun cancel(identifier: String) {
if (runnables.containsKey(identifier)) {
val old = runnables[identifier]
handler.removeCallbacks(old)
runnables.remove(identifier)
}
}
private fun insertRunnable(identifier: String, r: Runnable, millis: Long) {
val chained = Runnable {
handler.post(r)

View file

@ -0,0 +1,77 @@
/*
* Copyright 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.
*/
package im.vector.riotx.features.home.room.detail
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.floatingactionbutton.FloatingActionButton
import im.vector.riotx.core.utils.Debouncer
import timber.log.Timber
/**
* Show or hide the jumpToBottomView, depending on the scrolling and if the timeline is displaying the more recent event
* - When user scrolls up (i.e. going to the past): hide
* - When user scrolls down: show if not displaying last event
* - When user stops scrolling: show if not displaying last event
*/
class JumpToBottomViewVisibilityManager(
private val jumpToBottomView: FloatingActionButton,
private val debouncer: Debouncer,
recyclerView: RecyclerView,
private val layoutManager: LinearLayoutManager) {
init {
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
debouncer.cancel("jump_to_bottom_visibility")
val scrollingToPast = dy < 0
if (scrollingToPast) {
jumpToBottomView.hide()
} else {
maybeShowJumpToBottomViewVisibility()
}
}
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
when (newState) {
RecyclerView.SCROLL_STATE_IDLE -> {
maybeShowJumpToBottomViewVisibilityWithDelay()
}
RecyclerView.SCROLL_STATE_DRAGGING,
RecyclerView.SCROLL_STATE_SETTLING -> Unit
}
}
})
}
fun maybeShowJumpToBottomViewVisibilityWithDelay() {
debouncer.debounce("jump_to_bottom_visibility", 250, Runnable {
maybeShowJumpToBottomViewVisibility()
})
}
private fun maybeShowJumpToBottomViewVisibility() {
Timber.v("First visible: ${layoutManager.findFirstCompletelyVisibleItemPosition()}")
if (layoutManager.findFirstVisibleItemPosition() != 0) {
jumpToBottomView.show()
} else {
jumpToBottomView.hide()
}
}
}

View file

@ -177,6 +177,7 @@ class RoomDetailFragment @Inject constructor(
private lateinit var sharedActionViewModel: MessageSharedActionViewModel
private lateinit var layoutManager: LinearLayoutManager
private lateinit var jumpToBottomViewVisibilityManager: JumpToBottomViewVisibilityManager
private var modelBuildListener: OnModelBuildFinishedListener? = null
private lateinit var attachmentsHelper: AttachmentsHelper
@ -306,6 +307,13 @@ class RoomDetailFragment @Inject constructor(
layoutManager.scrollToPosition(0)
}
}
jumpToBottomViewVisibilityManager = JumpToBottomViewVisibilityManager(
jumpToBottomView,
debouncer,
recyclerView,
layoutManager
)
}
private fun setupJumpToReadMarkerView() {
@ -472,25 +480,11 @@ class RoomDetailFragment @Inject constructor(
it.dispatchTo(scrollOnNewMessageCallback)
it.dispatchTo(scrollOnHighlightedEventCallback)
updateJumpToReadMarkerViewVisibility()
updateJumpToBottomViewVisibility()
jumpToBottomViewVisibilityManager.maybeShowJumpToBottomViewVisibilityWithDelay()
}
timelineEventController.addModelBuildListener(modelBuildListener)
recyclerView.adapter = timelineEventController.adapter
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
when (newState) {
RecyclerView.SCROLL_STATE_IDLE -> {
updateJumpToBottomViewVisibility()
}
RecyclerView.SCROLL_STATE_DRAGGING,
RecyclerView.SCROLL_STATE_SETTLING -> {
jumpToBottomView.hide()
}
}
}
})
if (vectorPreferences.swipeToReplyIsEnabled()) {
val quickReplyHandler = object : RoomMessageTouchHelperCallback.QuickReplayHandler {
override fun performQuickReplyOnHolder(model: EpoxyModel<*>) {
@ -543,17 +537,6 @@ class RoomDetailFragment @Inject constructor(
}
}
private fun updateJumpToBottomViewVisibility() {
debouncer.debounce("jump_to_bottom_visibility", 250, Runnable {
Timber.v("First visible: ${layoutManager.findFirstCompletelyVisibleItemPosition()}")
if (layoutManager.findFirstVisibleItemPosition() != 0) {
jumpToBottomView.show()
} else {
jumpToBottomView.hide()
}
})
}
private fun setupComposer() {
autoCompleter.setup(composerLayout.composerEditText)
composerLayout.callback = object : TextComposerView.Callback {

View file

@ -48,6 +48,7 @@ class RoomDirectoryListCreator @Inject constructor(private val stringArrayProvid
if (it != userHsName) {
// Use the server name as a default display name
result.add(RoomDirectoryData(
homeServer = it,
displayName = it,
includeAllNetworks = true
))

View file

@ -20,13 +20,13 @@ import android.content.Intent
import android.net.Uri
import android.provider.Settings
import androidx.preference.Preference
import com.google.android.gms.oss.licenses.OssLicensesMenuActivity
import im.vector.matrix.android.api.Matrix
import im.vector.riotx.R
import im.vector.riotx.core.preference.VectorPreference
import im.vector.riotx.core.utils.copyToClipboard
import im.vector.riotx.core.utils.displayInWebView
import im.vector.riotx.features.version.VersionProvider
import im.vector.riotx.openOssLicensesMenuActivity
import javax.inject.Inject
class VectorSettingsHelpAboutFragment @Inject constructor(
@ -107,10 +107,11 @@ class VectorSettingsHelpAboutFragment @Inject constructor(
false
}
// Note: preference is not visible on F-Droid build
findPreference<VectorPreference>(VectorPreferences.SETTINGS_OTHER_THIRD_PARTY_NOTICES_PREFERENCE_KEY)!!
.onPreferenceClickListener = Preference.OnPreferenceClickListener {
// See https://developers.google.com/android/guides/opensource
startActivity(Intent(requireActivity(), OssLicensesMenuActivity::class.java))
openOssLicensesMenuActivity(requireActivity())
false
}
}

View file

@ -32,6 +32,7 @@
android:title="@string/settings_rageshake">
<im.vector.riotx.core.preference.VectorSwitchPreference
android:defaultValue="true"
android:key="SETTINGS_USE_RAGE_SHAKE_KEY"
android:title="@string/send_bug_report_rage_shake" />

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<im.vector.riotx.core.preference.VectorPreference
@ -40,6 +41,7 @@
<im.vector.riotx.core.preference.VectorPreference
android:key="SETTINGS_OTHER_THIRD_PARTY_NOTICES_PREFERENCE_KEY"
android:title="@string/settings_other_third_party_notices" />
android:title="@string/settings_other_third_party_notices"
app:isPreferenceVisible="@bool/isGplay" />
</androidx.preference.PreferenceScreen>