mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-25 19:05:56 +03:00
Merge branch 'develop' into feature/ons/fix_url_preview_on_edit
This commit is contained in:
commit
57dba2f29a
32 changed files with 344 additions and 191 deletions
|
@ -11,15 +11,17 @@ Bugfix 🐛:
|
|||
- Fix clear cache issue: sometimes, after a clear cache, there is still a token, so the init sync service is not started.
|
||||
- Sidebar too large in horizontal orientation or tablets (#475)
|
||||
- UrlPreview should be updated when the url is edited and changed (#2678)
|
||||
- When receiving a new pepper from identity server, use it on the next hash lookup (#2708)
|
||||
- Crashes reported by PlayStore (new in 1.0.14) (#2707)
|
||||
|
||||
Translations 🗣:
|
||||
-
|
||||
|
||||
SDK API changes ⚠️:
|
||||
-
|
||||
- Increase targetSdkVersion to 30 (#2600)
|
||||
|
||||
Build 🧱:
|
||||
-
|
||||
- Compile with Android SDK 30 (Android 11)
|
||||
|
||||
Test:
|
||||
-
|
||||
|
|
|
@ -32,11 +32,11 @@ buildscript {
|
|||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
compileSdkVersion 30
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 29
|
||||
targetSdkVersion 30
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
|
|
|
@ -18,15 +18,19 @@
|
|||
package im.vector.lib.attachmentviewer
|
||||
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.GestureDetector
|
||||
import android.view.MotionEvent
|
||||
import android.view.ScaleGestureDetector
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowInsets
|
||||
import android.view.WindowInsetsController
|
||||
import android.view.WindowManager
|
||||
import android.widget.ImageView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.GestureDetectorCompat
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.isVisible
|
||||
|
@ -94,14 +98,7 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
|
|||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
// This is important for the dispatchTouchEvent, if not we must correct
|
||||
// the touch coordinates
|
||||
window.decorView.systemUiVisibility = (
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
or View.SYSTEM_UI_FLAG_IMMERSIVE)
|
||||
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
|
||||
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
|
||||
setDecorViewFullScreen()
|
||||
|
||||
views = ActivityAttachmentViewerBinding.inflate(layoutInflater)
|
||||
setContentView(views.root)
|
||||
|
@ -134,6 +131,29 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private fun setDecorViewFullScreen() {
|
||||
// This is important for the dispatchTouchEvent, if not we must correct
|
||||
// the touch coordinates
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
// New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
window.setDecorFitsSystemWindows(false)
|
||||
// New API instead of SYSTEM_UI_FLAG_IMMERSIVE
|
||||
window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE
|
||||
// New API instead of FLAG_TRANSLUCENT_STATUS
|
||||
window.statusBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar)
|
||||
// new API instead of FLAG_TRANSLUCENT_NAVIGATION
|
||||
window.navigationBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar)
|
||||
} else {
|
||||
window.decorView.systemUiVisibility = (
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
or View.SYSTEM_UI_FLAG_IMMERSIVE)
|
||||
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
|
||||
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
|
||||
}
|
||||
}
|
||||
|
||||
fun onSelectedPositionChanged(position: Int) {
|
||||
attachmentsAdapter.recyclerView?.findViewHolderForAdapterPosition(currentPosition)?.let {
|
||||
(it as? BaseViewHolder)?.onSelected(false)
|
||||
|
@ -313,28 +333,48 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
|
|||
?.handleCommand(commands)
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private fun hideSystemUI() {
|
||||
systemUiVisibility = false
|
||||
// Enables regular immersive mode.
|
||||
// For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE.
|
||||
// Or for "sticky immersive," replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE
|
||||
// Set the content to appear under the system bars so that the
|
||||
// content doesn't resize when the system bars hide and show.
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
// Hide the nav bar and status bar
|
||||
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_FULLSCREEN)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
// New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
window.setDecorFitsSystemWindows(false)
|
||||
// new API instead of SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
window.decorView.windowInsetsController?.hide(WindowInsets.Type.navigationBars())
|
||||
// New API instead of SYSTEM_UI_FLAG_IMMERSIVE
|
||||
window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE
|
||||
// New API instead of FLAG_TRANSLUCENT_STATUS
|
||||
window.statusBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar)
|
||||
// New API instead of FLAG_TRANSLUCENT_NAVIGATION
|
||||
window.navigationBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar)
|
||||
} else {
|
||||
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE
|
||||
// Set the content to appear under the system bars so that the
|
||||
// content doesn't resize when the system bars hide and show.
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
// Hide the nav bar and status bar
|
||||
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_FULLSCREEN)
|
||||
}
|
||||
}
|
||||
|
||||
// Shows the system bars by removing all the flags
|
||||
// except for the ones that make the content appear under the system bars.
|
||||
@Suppress("DEPRECATION")
|
||||
private fun showSystemUI() {
|
||||
systemUiVisibility = true
|
||||
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
// New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
window.setDecorFitsSystemWindows(false)
|
||||
} else {
|
||||
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
6
attachment-viewer/src/main/res/values/colors.xml
Normal file
6
attachment-viewer/src/main/res/values/colors.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<resources>
|
||||
|
||||
<color name="half_transparent_status_bar">#80000000</color>
|
||||
|
||||
</resources>
|
5
gradle/wrapper/gradle-wrapper.properties
vendored
5
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,7 +1,6 @@
|
|||
#Fri Jan 15 11:30:47 CET 2021
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=a7ca23b3ccf265680f2bfd35f1f00b1424f4466292c7337c85d46c9641b3f053
|
||||
distributionSha256Sum=3db89524a3981819ff28c3f979236c1274a726e146ced0c8a2020417f9bc0782
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-all.zip
|
||||
|
|
|
@ -3,11 +3,11 @@ apply plugin: 'kotlin-android'
|
|||
apply plugin: 'kotlin-kapt'
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
compileSdkVersion 30
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 29
|
||||
targetSdkVersion 30
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
|
|
|
@ -14,12 +14,12 @@ buildscript {
|
|||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
compileSdkVersion 30
|
||||
testOptions.unitTests.includeAndroidResources = true
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 29
|
||||
targetSdkVersion 30
|
||||
versionCode 1
|
||||
versionName "0.0.1"
|
||||
// Multidex is useful for tests
|
||||
|
|
|
@ -47,22 +47,24 @@ internal object ThumbnailExtractor {
|
|||
val mediaMetadataRetriever = MediaMetadataRetriever()
|
||||
try {
|
||||
mediaMetadataRetriever.setDataSource(context, attachment.queryUri)
|
||||
val thumbnail = mediaMetadataRetriever.frameAtTime
|
||||
|
||||
val outputStream = ByteArrayOutputStream()
|
||||
thumbnail.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
|
||||
val thumbnailWidth = thumbnail.width
|
||||
val thumbnailHeight = thumbnail.height
|
||||
val thumbnailSize = outputStream.size()
|
||||
thumbnailData = ThumbnailData(
|
||||
width = thumbnailWidth,
|
||||
height = thumbnailHeight,
|
||||
size = thumbnailSize.toLong(),
|
||||
bytes = outputStream.toByteArray(),
|
||||
mimeType = MimeTypes.Jpeg
|
||||
)
|
||||
thumbnail.recycle()
|
||||
outputStream.reset()
|
||||
mediaMetadataRetriever.frameAtTime?.let { thumbnail ->
|
||||
val outputStream = ByteArrayOutputStream()
|
||||
thumbnail.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
|
||||
val thumbnailWidth = thumbnail.width
|
||||
val thumbnailHeight = thumbnail.height
|
||||
val thumbnailSize = outputStream.size()
|
||||
thumbnailData = ThumbnailData(
|
||||
width = thumbnailWidth,
|
||||
height = thumbnailHeight,
|
||||
size = thumbnailSize.toLong(),
|
||||
bytes = outputStream.toByteArray(),
|
||||
mimeType = MimeTypes.Jpeg
|
||||
)
|
||||
thumbnail.recycle()
|
||||
outputStream.reset()
|
||||
} ?: run {
|
||||
Timber.e("Cannot extract video thumbnail at %s", attachment.queryUri.toString())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Cannot extract video thumbnail")
|
||||
} finally {
|
||||
|
|
|
@ -52,65 +52,60 @@ internal class DefaultIdentityBulkLookupTask @Inject constructor(
|
|||
val pepper = identityData.hashLookupPepper
|
||||
val hashDetailResponse = if (pepper == null) {
|
||||
// We need to fetch the hash details first
|
||||
fetchAndStoreHashDetails(identityAPI)
|
||||
fetchHashDetails(identityAPI)
|
||||
.also { identityStore.setHashDetails(it) }
|
||||
} else {
|
||||
IdentityHashDetailResponse(pepper, identityData.hashLookupAlgorithm)
|
||||
}
|
||||
|
||||
if (hashDetailResponse.algorithms.contains("sha256").not()) {
|
||||
if (hashDetailResponse.algorithms.contains(IdentityHashDetailResponse.ALGORITHM_SHA256).not()) {
|
||||
// TODO We should ask the user if he is ok to send their 3Pid in clear, but for the moment we do not do it
|
||||
// Also, what we have in cache could be outdated, the identity server maybe now supports sha256
|
||||
throw IdentityServiceError.BulkLookupSha256NotSupported
|
||||
}
|
||||
|
||||
val hashedAddresses = withOlmUtility { olmUtility ->
|
||||
params.threePids.map { threePid ->
|
||||
base64ToBase64Url(
|
||||
olmUtility.sha256(threePid.value.toLowerCase(Locale.ROOT)
|
||||
+ " " + threePid.toMedium() + " " + hashDetailResponse.pepper)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val identityLookUpV2Response = lookUpInternal(identityAPI, hashedAddresses, hashDetailResponse, true)
|
||||
val lookUpData = lookUpInternal(identityAPI, params.threePids, hashDetailResponse, true)
|
||||
|
||||
// Convert back to List<FoundThreePid>
|
||||
return handleSuccess(params.threePids, hashedAddresses, identityLookUpV2Response)
|
||||
return handleSuccess(params.threePids, lookUpData)
|
||||
}
|
||||
|
||||
data class LookUpData(
|
||||
val hashedAddresses: List<String>,
|
||||
val identityLookUpResponse: IdentityLookUpResponse
|
||||
)
|
||||
|
||||
private suspend fun lookUpInternal(identityAPI: IdentityAPI,
|
||||
hashedAddresses: List<String>,
|
||||
threePids: List<ThreePid>,
|
||||
hashDetailResponse: IdentityHashDetailResponse,
|
||||
canRetry: Boolean): IdentityLookUpResponse {
|
||||
canRetry: Boolean): LookUpData {
|
||||
val hashedAddresses = getHashedAddresses(threePids, hashDetailResponse.pepper)
|
||||
return try {
|
||||
executeRequest(null) {
|
||||
apiCall = identityAPI.lookup(IdentityLookUpParams(
|
||||
hashedAddresses,
|
||||
IdentityHashDetailResponse.ALGORITHM_SHA256,
|
||||
hashDetailResponse.pepper
|
||||
))
|
||||
}
|
||||
LookUpData(hashedAddresses,
|
||||
executeRequest(null) {
|
||||
apiCall = identityAPI.lookup(IdentityLookUpParams(
|
||||
hashedAddresses,
|
||||
IdentityHashDetailResponse.ALGORITHM_SHA256,
|
||||
hashDetailResponse.pepper
|
||||
))
|
||||
})
|
||||
} catch (failure: Throwable) {
|
||||
// Catch invalid hash pepper and retry
|
||||
if (canRetry && failure is Failure.ServerError && failure.error.code == MatrixError.M_INVALID_PEPPER) {
|
||||
// This is not documented, but the error can contain the new pepper!
|
||||
if (!failure.error.newLookupPepper.isNullOrEmpty()) {
|
||||
val newHashDetailResponse = if (!failure.error.newLookupPepper.isNullOrEmpty()) {
|
||||
// Store it and use it right now
|
||||
hashDetailResponse.copy(pepper = failure.error.newLookupPepper)
|
||||
.also { identityStore.setHashDetails(it) }
|
||||
.let { lookUpInternal(identityAPI, hashedAddresses, it, false /* Avoid infinite loop */) }
|
||||
} else {
|
||||
// Retrieve the new hash details
|
||||
val newHashDetailResponse = fetchAndStoreHashDetails(identityAPI)
|
||||
|
||||
if (hashDetailResponse.algorithms.contains(IdentityHashDetailResponse.ALGORITHM_SHA256).not()) {
|
||||
// TODO We should ask the user if he is ok to send their 3Pid in clear, but for the moment we do not do it
|
||||
// Also, what we have in cache is maybe outdated, the identity server maybe now support sha256
|
||||
throw IdentityServiceError.BulkLookupSha256NotSupported
|
||||
}
|
||||
|
||||
lookUpInternal(identityAPI, hashedAddresses, newHashDetailResponse, false /* Avoid infinite loop */)
|
||||
fetchHashDetails(identityAPI)
|
||||
}
|
||||
.also { identityStore.setHashDetails(it) }
|
||||
if (newHashDetailResponse.algorithms.contains(IdentityHashDetailResponse.ALGORITHM_SHA256).not()) {
|
||||
// TODO We should ask the user if he is ok to send their 3Pid in clear, but for the moment we do not do it
|
||||
throw IdentityServiceError.BulkLookupSha256NotSupported
|
||||
}
|
||||
lookUpInternal(identityAPI, threePids, newHashDetailResponse, false /* Avoid infinite loop */)
|
||||
} else {
|
||||
// Other error
|
||||
throw failure
|
||||
|
@ -118,16 +113,29 @@ internal class DefaultIdentityBulkLookupTask @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun fetchAndStoreHashDetails(identityAPI: IdentityAPI): IdentityHashDetailResponse {
|
||||
return executeRequest<IdentityHashDetailResponse>(null) {
|
||||
apiCall = identityAPI.hashDetails()
|
||||
private fun getHashedAddresses(threePids: List<ThreePid>, pepper: String): List<String> {
|
||||
return withOlmUtility { olmUtility ->
|
||||
threePids.map { threePid ->
|
||||
base64ToBase64Url(
|
||||
olmUtility.sha256(threePid.value.toLowerCase(Locale.ROOT)
|
||||
+ " " + threePid.toMedium() + " " + pepper)
|
||||
)
|
||||
}
|
||||
}
|
||||
.also { identityStore.setHashDetails(it) }
|
||||
}
|
||||
|
||||
private fun handleSuccess(threePids: List<ThreePid>, hashedAddresses: List<String>, identityLookUpResponse: IdentityLookUpResponse): List<FoundThreePid> {
|
||||
return identityLookUpResponse.mappings.keys.map { hashedAddress ->
|
||||
FoundThreePid(threePids[hashedAddresses.indexOf(hashedAddress)], identityLookUpResponse.mappings[hashedAddress] ?: error(""))
|
||||
private suspend fun fetchHashDetails(identityAPI: IdentityAPI): IdentityHashDetailResponse {
|
||||
return executeRequest(null) {
|
||||
apiCall = identityAPI.hashDetails()
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSuccess(threePids: List<ThreePid>, lookupData: LookUpData): List<FoundThreePid> {
|
||||
return lookupData.identityLookUpResponse.mappings.keys.map { hashedAddress ->
|
||||
FoundThreePid(
|
||||
threePids[lookupData.hashedAddresses.indexOf(hashedAddress)],
|
||||
lookupData.identityLookUpResponse.mappings[hashedAddress] ?: error("")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,16 +21,34 @@ import com.squareup.moshi.JsonClass
|
|||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class EventContextResponse(
|
||||
internal data class EventContextResponse(
|
||||
/**
|
||||
* Details of the requested event.
|
||||
*/
|
||||
@Json(name = "event") val event: Event,
|
||||
/**
|
||||
* A token that can be used to paginate backwards with.
|
||||
*/
|
||||
@Json(name = "start") override val start: String? = null,
|
||||
@Json(name = "events_before") val eventsBefore: List<Event> = emptyList(),
|
||||
@Json(name = "events_after") val eventsAfter: List<Event> = emptyList(),
|
||||
/**
|
||||
* A list of room events that happened just before the requested event, in reverse-chronological order.
|
||||
*/
|
||||
@Json(name = "events_before") val eventsBefore: List<Event>? = null,
|
||||
/**
|
||||
* A list of room events that happened just after the requested event, in chronological order.
|
||||
*/
|
||||
@Json(name = "events_after") val eventsAfter: List<Event>? = null,
|
||||
/**
|
||||
* A token that can be used to paginate forwards with.
|
||||
*/
|
||||
@Json(name = "end") override val end: String? = null,
|
||||
@Json(name = "state") override val stateEvents: List<Event> = emptyList()
|
||||
/**
|
||||
* The state of the room at the last event returned.
|
||||
*/
|
||||
@Json(name = "state") override val stateEvents: List<Event>? = null
|
||||
) : TokenChunkEvent {
|
||||
|
||||
override val events: List<Event> by lazy {
|
||||
eventsAfter.reversed() + listOf(event) + eventsBefore
|
||||
eventsAfter.orEmpty().reversed() + event + eventsBefore.orEmpty()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,8 +22,28 @@ import org.matrix.android.sdk.api.session.events.model.Event
|
|||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class PaginationResponse(
|
||||
/**
|
||||
* The token the pagination starts from. If dir=b this will be the token supplied in from.
|
||||
*/
|
||||
@Json(name = "start") override val start: String? = null,
|
||||
/**
|
||||
* The token the pagination ends at. If dir=b this token should be used again to request even earlier events.
|
||||
*/
|
||||
@Json(name = "end") override val end: String? = null,
|
||||
@Json(name = "chunk") override val events: List<Event> = emptyList(),
|
||||
@Json(name = "state") override val stateEvents: List<Event> = emptyList()
|
||||
) : TokenChunkEvent
|
||||
/**
|
||||
* A list of room events. The order depends on the dir parameter. For dir=b events will be in
|
||||
* reverse-chronological order, for dir=f in chronological order, so that events start at the from point.
|
||||
*/
|
||||
@Json(name = "chunk") val chunk: List<Event>? = null,
|
||||
/**
|
||||
* A list of state events relevant to showing the chunk. For example, if lazy_load_members is enabled
|
||||
* in the filter then this may contain the membership events for the senders of events in the chunk.
|
||||
*
|
||||
* Unless include_redundant_members is true, the server may remove membership events which would have
|
||||
* already been sent to the client in prior calls to this endpoint, assuming the membership of those members has not changed.
|
||||
*/
|
||||
@Json(name = "state") override val stateEvents: List<Event>? = null
|
||||
) : TokenChunkEvent {
|
||||
override val events: List<Event>
|
||||
get() = chunk.orEmpty()
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ internal interface TokenChunkEvent {
|
|||
val start: String?
|
||||
val end: String?
|
||||
val events: List<Event>
|
||||
val stateEvents: List<Event>
|
||||
val stateEvents: List<Event>?
|
||||
|
||||
fun hasMore() = start != end
|
||||
}
|
||||
|
|
|
@ -156,7 +156,7 @@ internal class TokenChunkEventPersistor @Inject constructor(@SessionDatabase pri
|
|||
}
|
||||
}
|
||||
return if (receivedChunk.events.isEmpty()) {
|
||||
if (receivedChunk.start != receivedChunk.end) {
|
||||
if (receivedChunk.hasMore()) {
|
||||
Result.SHOULD_FETCH_MORE
|
||||
} else {
|
||||
Result.REACHED_END
|
||||
|
@ -196,7 +196,7 @@ internal class TokenChunkEventPersistor @Inject constructor(@SessionDatabase pri
|
|||
|
||||
val now = System.currentTimeMillis()
|
||||
|
||||
for (stateEvent in stateEvents) {
|
||||
stateEvents?.forEach { stateEvent ->
|
||||
val ageLocalTs = stateEvent.unsignedData?.age?.let { now - it }
|
||||
val stateEventEntity = stateEvent.toEntity(roomId, SendState.SYNCED, ageLocalTs).copyToRealmOrIgnore(realm, EventInsertType.PAGINATION)
|
||||
currentChunk.addStateEvent(roomId, stateEventEntity, direction)
|
||||
|
@ -205,9 +205,9 @@ internal class TokenChunkEventPersistor @Inject constructor(@SessionDatabase pri
|
|||
}
|
||||
}
|
||||
val eventIds = ArrayList<String>(eventList.size)
|
||||
for (event in eventList) {
|
||||
eventList.forEach { event ->
|
||||
if (event.eventId == null || event.senderId == null) {
|
||||
continue
|
||||
return@forEach
|
||||
}
|
||||
val ageLocalTs = event.unsignedData?.age?.let { now - it }
|
||||
eventIds.add(event.eventId)
|
||||
|
|
|
@ -56,8 +56,8 @@ internal class DefaultGetUploadsTask @Inject constructor(
|
|||
private val roomAPI: RoomAPI,
|
||||
private val tokenStore: SyncTokenStore,
|
||||
@SessionDatabase private val monarchy: Monarchy,
|
||||
private val globalErrorReceiver: GlobalErrorReceiver)
|
||||
: GetUploadsTask {
|
||||
private val globalErrorReceiver: GlobalErrorReceiver
|
||||
) : GetUploadsTask {
|
||||
|
||||
override suspend fun execute(params: GetUploadsTask.Params): GetUploadsResult {
|
||||
val result: GetUploadsResult
|
||||
|
|
|
@ -19,11 +19,11 @@ apply plugin: 'kotlin-android'
|
|||
apply plugin: 'kotlin-parcelize'
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
compileSdkVersion 30
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 29
|
||||
targetSdkVersion 30
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ class AudioPicker : Picker<MultiPickerAudioType>() {
|
|||
context.contentResolver.openFileDescriptor(selectedUri, "r")?.use { pfd ->
|
||||
val mediaMetadataRetriever = MediaMetadataRetriever()
|
||||
mediaMetadataRetriever.setDataSource(pfd.fileDescriptor)
|
||||
duration = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION).toLong()
|
||||
duration = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLong() ?: 0L
|
||||
}
|
||||
|
||||
audioList.add(
|
||||
|
|
|
@ -61,10 +61,10 @@ class VideoPicker : Picker<MultiPickerVideoType>() {
|
|||
context.contentResolver.openFileDescriptor(selectedUri, "r")?.use { pfd ->
|
||||
val mediaMetadataRetriever = MediaMetadataRetriever()
|
||||
mediaMetadataRetriever.setDataSource(pfd.fileDescriptor)
|
||||
duration = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION).toLong()
|
||||
width = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH).toInt()
|
||||
height = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT).toInt()
|
||||
orientation = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION).toInt()
|
||||
duration = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLong() ?: 0L
|
||||
width = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)?.toInt() ?: 0
|
||||
height = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)?.toInt() ?: 0
|
||||
orientation = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION)?.toInt() ?: 0
|
||||
}
|
||||
|
||||
videoList.add(
|
||||
|
|
|
@ -101,7 +101,7 @@ ext.abiVersionCodes = ["armeabi-v7a": 1, "arm64-v8a": 2, "x86": 3, "x86_64": 4].
|
|||
def buildNumber = System.env.BUILDKITE_BUILD_NUMBER as Integer ?: 0
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
compileSdkVersion 30
|
||||
|
||||
// Due to a bug introduced in Android gradle plugin 3.6.0, we have to specify the ndk version to use
|
||||
// Ref: https://issuetracker.google.com/issues/144111441
|
||||
|
@ -111,7 +111,7 @@ android {
|
|||
applicationId "im.vector.app"
|
||||
// Set to API 21: see #405
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 29
|
||||
targetSdkVersion 30
|
||||
multiDexEnabled true
|
||||
|
||||
// `develop` branch will have version code from timestamp, to ensure each build from CI has a incremented versionCode.
|
||||
|
|
|
@ -196,6 +196,8 @@ class UiAllScreensSanityTest {
|
|||
pressBack()
|
||||
clickMenu(R.id.video_call)
|
||||
pressBack()
|
||||
clickMenu(R.id.search)
|
||||
pressBack()
|
||||
|
||||
pressBack()
|
||||
}
|
||||
|
|
|
@ -19,10 +19,12 @@ package im.vector.app.core.platform
|
|||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.WindowInsetsController
|
||||
import android.view.WindowManager
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.AttrRes
|
||||
|
@ -33,6 +35,7 @@ import androidx.annotation.StringRes
|
|||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentFactory
|
||||
|
@ -410,13 +413,25 @@ abstract class VectorBaseActivity<VB: ViewBinding> : AppCompatActivity(), HasScr
|
|||
/**
|
||||
* Force to render the activity in fullscreen
|
||||
*/
|
||||
@Suppress("DEPRECATION")
|
||||
private fun setFullScreen() {
|
||||
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
// New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
window.setDecorFitsSystemWindows(false)
|
||||
// New API instead of SYSTEM_UI_FLAG_IMMERSIVE
|
||||
window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE
|
||||
// New API instead of FLAG_TRANSLUCENT_STATUS
|
||||
window.statusBarColor = ContextCompat.getColor(this, im.vector.lib.attachmentviewer.R.color.half_transparent_status_bar)
|
||||
// New API instead of FLAG_TRANSLUCENT_NAVIGATION
|
||||
window.navigationBarColor = ContextCompat.getColor(this, im.vector.lib.attachmentviewer.R.color.half_transparent_status_bar)
|
||||
} else {
|
||||
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
|
||||
}
|
||||
}
|
||||
|
||||
/* ==========================================================================================
|
||||
|
|
|
@ -19,6 +19,7 @@ package im.vector.app.features.attachments.preview
|
|||
|
||||
import android.app.Activity.RESULT_CANCELED
|
||||
import android.app.Activity.RESULT_OK
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.LayoutInflater
|
||||
|
@ -153,8 +154,13 @@ class AttachmentsPreviewFragment @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private fun applyInsets() {
|
||||
view?.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
activity?.window?.setDecorFitsSystemWindows(false)
|
||||
} else {
|
||||
view?.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
}
|
||||
ViewCompat.setOnApplyWindowInsetsListener(views.attachmentPreviewerBottomContainer) { v, insets ->
|
||||
v.updatePadding(bottom = insets.systemWindowInsetBottom)
|
||||
insets
|
||||
|
|
|
@ -48,7 +48,7 @@ class CallAudioManager(
|
|||
|
||||
private var savedIsSpeakerPhoneOn = false
|
||||
private var savedIsMicrophoneMute = false
|
||||
private var savedAudioMode = AudioManager.MODE_INVALID
|
||||
private var savedAudioMode = AudioManager.MODE_NORMAL
|
||||
|
||||
private var connectedBlueToothHeadset: BluetoothProfile? = null
|
||||
private var wantsBluetoothConnection = false
|
||||
|
|
|
@ -25,8 +25,11 @@ import android.os.Bundle
|
|||
import android.os.Parcelable
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
import android.view.WindowInsets
|
||||
import android.view.WindowInsetsController
|
||||
import android.view.WindowManager
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.isInvisible
|
||||
|
@ -102,29 +105,49 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
|
|||
setContentView(R.layout.activity_call)
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private fun hideSystemUI() {
|
||||
systemUiVisibility = false
|
||||
// Enables regular immersive mode.
|
||||
// For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE.
|
||||
// Or for "sticky immersive," replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE
|
||||
// Set the content to appear under the system bars so that the
|
||||
// content doesn't resize when the system bars hide and show.
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
// Hide the nav bar and status bar
|
||||
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_FULLSCREEN)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
// New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
window.setDecorFitsSystemWindows(false)
|
||||
// New API instead of SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
window.decorView.windowInsetsController?.hide(WindowInsets.Type.navigationBars())
|
||||
// New API instead of SYSTEM_UI_FLAG_IMMERSIVE
|
||||
window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE
|
||||
// New API instead of FLAG_TRANSLUCENT_STATUS
|
||||
window.statusBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar)
|
||||
// New API instead of FLAG_TRANSLUCENT_NAVIGATION
|
||||
window.navigationBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar)
|
||||
} else {
|
||||
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE
|
||||
// Set the content to appear under the system bars so that the
|
||||
// content doesn't resize when the system bars hide and show.
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
// Hide the nav bar and status bar
|
||||
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_FULLSCREEN)
|
||||
}
|
||||
}
|
||||
|
||||
// Shows the system bars by removing all the flags
|
||||
// except for the ones that make the content appear under the system bars.
|
||||
@Suppress("DEPRECATION")
|
||||
private fun showSystemUI() {
|
||||
systemUiVisibility = true
|
||||
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
// New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
window.setDecorFitsSystemWindows(false)
|
||||
} else {
|
||||
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
|
||||
}
|
||||
}
|
||||
|
||||
private fun toggleUiSystemVisibility() {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package im.vector.app.features.crypto.recover
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.KeyEvent
|
||||
|
@ -102,7 +103,12 @@ class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetBoot
|
|||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
val rootView = super.onCreateView(inflater, container, savedInstanceState)
|
||||
dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
dialog?.window?.setDecorFitsSystemWindows(false)
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
|
||||
}
|
||||
return rootView
|
||||
}
|
||||
|
||||
|
|
|
@ -297,6 +297,8 @@ class RoomDetailFragment @Inject constructor(
|
|||
private var lockSendButton = false
|
||||
private val activeCallViewHolder = ActiveCallViewHolder()
|
||||
|
||||
private lateinit var emojiPopup: EmojiPopup
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java)
|
||||
|
@ -512,7 +514,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
}
|
||||
|
||||
private fun setupEmojiPopup() {
|
||||
val emojiPopup = EmojiPopup
|
||||
emojiPopup = EmojiPopup
|
||||
.Builder
|
||||
.fromRootView(views.rootConstraintLayout)
|
||||
.setKeyboardAnimationStyle(R.style.emoji_fade_animation_style)
|
||||
|
@ -591,6 +593,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
autoCompleter.clear()
|
||||
debouncer.cancelAll()
|
||||
views.timelineRecyclerView.cleanup()
|
||||
emojiPopup.dismiss()
|
||||
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
|
|
@ -76,10 +76,10 @@ class SearchFragment @Inject constructor(
|
|||
controller.listener = this
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
override fun onDestroyView() {
|
||||
views.searchResultRecycler.cleanup()
|
||||
controller.listener = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun invalidate() = withState(searchViewModel) { state ->
|
||||
|
|
|
@ -155,18 +155,15 @@ class LoginWebFragment @Inject constructor(
|
|||
// avoid infinite onPageFinished call
|
||||
if (url.startsWith("http")) {
|
||||
// Generic method to make a bridge between JS and the UIWebView
|
||||
val mxcJavascriptSendObjectMessage = assetReader.readAssetFile("sendObject.js")
|
||||
view.loadUrl(mxcJavascriptSendObjectMessage)
|
||||
assetReader.readAssetFile("sendObject.js")?.let { view.loadUrl(it) }
|
||||
|
||||
if (state.signMode == SignMode.SignIn) {
|
||||
// The function the fallback page calls when the login is complete
|
||||
val mxcJavascriptOnLogin = assetReader.readAssetFile("onLogin.js")
|
||||
view.loadUrl(mxcJavascriptOnLogin)
|
||||
assetReader.readAssetFile("onLogin.js")?.let { view.loadUrl(it) }
|
||||
} else {
|
||||
// MODE_REGISTER
|
||||
// The function the fallback page calls when the registration is complete
|
||||
val mxcJavascriptOnRegistered = assetReader.readAssetFile("onRegistered.js")
|
||||
view.loadUrl(mxcJavascriptOnRegistered)
|
||||
assetReader.readAssetFile("onRegistered.js")?.let { view.loadUrl(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import android.os.Build
|
|||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.View
|
||||
import android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
|
||||
import android.widget.ImageView
|
||||
import com.tapadoo.alerter.Alerter
|
||||
import com.tapadoo.alerter.OnHideAlertListener
|
||||
|
@ -165,9 +166,7 @@ class PopupAlertManager @Inject constructor(private val avatarRenderer: Lazy<Ava
|
|||
?.takeIf { ThemeUtils.isLightTheme(it) }
|
||||
?.let { it.window?.decorView }
|
||||
?.let { view ->
|
||||
var flags = view.systemUiVisibility
|
||||
flags = flags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
|
||||
view.systemUiVisibility = flags
|
||||
view.windowInsetsController?.setSystemBarsAppearance(0, APPEARANCE_LIGHT_STATUS_BARS)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,9 +178,7 @@ class PopupAlertManager @Inject constructor(private val avatarRenderer: Lazy<Ava
|
|||
?.takeIf { ThemeUtils.isLightTheme(it) }
|
||||
?.let { it.window?.decorView }
|
||||
?.let { view ->
|
||||
var flags = view.systemUiVisibility
|
||||
flags = flags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
|
||||
view.systemUiVisibility = flags
|
||||
view.windowInsetsController?.setSystemBarsAppearance(APPEARANCE_LIGHT_STATUS_BARS, APPEARANCE_LIGHT_STATUS_BARS)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@ import android.content.Context
|
|||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import android.os.AsyncTask
|
||||
import android.os.Build
|
||||
import android.view.View
|
||||
import androidx.fragment.app.DialogFragment
|
||||
|
@ -37,6 +36,11 @@ import im.vector.app.features.settings.devtools.GossipingEventsSerializer
|
|||
import im.vector.app.features.settings.locale.SystemLocaleProvider
|
||||
import im.vector.app.features.themes.ThemeUtils
|
||||
import im.vector.app.features.version.VersionProvider
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.Call
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.OkHttpClient
|
||||
|
@ -98,6 +102,8 @@ class BugReporter @Inject constructor(
|
|||
var screenshot: Bitmap? = null
|
||||
private set
|
||||
|
||||
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
|
||||
|
||||
private val LOGCAT_CMD_ERROR = arrayOf("logcat", // /< Run 'logcat' command
|
||||
"-d", // /< Dump the log rather than continue outputting it
|
||||
"-v", // formatting
|
||||
|
@ -160,13 +166,13 @@ class BugReporter @Inject constructor(
|
|||
withScreenshot: Boolean,
|
||||
theBugDescription: String,
|
||||
listener: IMXBugReportListener?) {
|
||||
object : AsyncTask<Void, Int, String>() {
|
||||
// enumerate files to delete
|
||||
val mBugReportFiles: MutableList<File> = ArrayList()
|
||||
// enumerate files to delete
|
||||
val mBugReportFiles: MutableList<File> = ArrayList()
|
||||
|
||||
override fun doInBackground(vararg voids: Void?): String? {
|
||||
coroutineScope.launch {
|
||||
var serverError: String? = null
|
||||
withContext(Dispatchers.IO) {
|
||||
var bugDescription = theBugDescription
|
||||
var serverError: String? = null
|
||||
val crashCallStack = getCrashDescription(context)
|
||||
|
||||
if (null != crashCallStack) {
|
||||
|
@ -342,7 +348,11 @@ class BugReporter @Inject constructor(
|
|||
}
|
||||
|
||||
Timber.v("## onWrite() : $percentage%")
|
||||
publishProgress(percentage)
|
||||
try {
|
||||
listener?.onProgress(percentage)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## onProgress() : failed")
|
||||
}
|
||||
}
|
||||
|
||||
// build the request
|
||||
|
@ -386,11 +396,13 @@ class BugReporter @Inject constructor(
|
|||
}
|
||||
|
||||
// check if the error message
|
||||
try {
|
||||
val responseJSON = JSONObject(serverError)
|
||||
serverError = responseJSON.getString("error")
|
||||
} catch (e: JSONException) {
|
||||
Timber.e(e, "doInBackground ; Json conversion failed")
|
||||
serverError?.let {
|
||||
try {
|
||||
val responseJSON = JSONObject(it)
|
||||
serverError = responseJSON.getString("error")
|
||||
} catch (e: JSONException) {
|
||||
Timber.e(e, "doInBackground ; Json conversion failed")
|
||||
}
|
||||
}
|
||||
|
||||
// should never happen
|
||||
|
@ -403,21 +415,9 @@ class BugReporter @Inject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return serverError
|
||||
}
|
||||
|
||||
override fun onProgressUpdate(vararg progress: Int?) {
|
||||
if (null != listener) {
|
||||
try {
|
||||
listener.onProgress(progress[0] ?: 0)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## onProgress() : failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPostExecute(reason: String?) {
|
||||
withContext(Dispatchers.Main) {
|
||||
mBugReportCall = null
|
||||
|
||||
// delete when the bug report has been successfully sent
|
||||
|
@ -429,17 +429,17 @@ class BugReporter @Inject constructor(
|
|||
try {
|
||||
if (mIsCancelled) {
|
||||
listener.onUploadCancelled()
|
||||
} else if (null == reason) {
|
||||
} else if (null == serverError) {
|
||||
listener.onUploadSucceed()
|
||||
} else {
|
||||
listener.onUploadFailed(reason)
|
||||
listener.onUploadFailed(serverError)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## onPostExecute() : failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
}.execute()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -457,9 +457,9 @@ class BugReporter @Inject constructor(
|
|||
activity.startActivity(intent)
|
||||
}
|
||||
|
||||
// ==============================================================================================================
|
||||
// crash report management
|
||||
// ==============================================================================================================
|
||||
// ==============================================================================================================
|
||||
// crash report management
|
||||
// ==============================================================================================================
|
||||
|
||||
/**
|
||||
* Provides the crash file
|
||||
|
@ -529,9 +529,9 @@ class BugReporter @Inject constructor(
|
|||
return null
|
||||
}
|
||||
|
||||
// ==============================================================================================================
|
||||
// Screenshot management
|
||||
// ==============================================================================================================
|
||||
// ==============================================================================================================
|
||||
// Screenshot management
|
||||
// ==============================================================================================================
|
||||
|
||||
/**
|
||||
* Take a screenshot of the display.
|
||||
|
@ -598,9 +598,9 @@ class BugReporter @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
// ==============================================================================================================
|
||||
// Logcat management
|
||||
// ==============================================================================================================
|
||||
// ==============================================================================================================
|
||||
// Logcat management
|
||||
// ==============================================================================================================
|
||||
|
||||
/**
|
||||
* Save the logcat
|
||||
|
@ -660,9 +660,9 @@ class BugReporter @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
// ==============================================================================================================
|
||||
// File compression management
|
||||
// ==============================================================================================================
|
||||
// ==============================================================================================================
|
||||
// File compression management
|
||||
// ==============================================================================================================
|
||||
|
||||
/**
|
||||
* GZip a file
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package im.vector.app.features.roomprofile.uploads.media
|
||||
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.LayoutInflater
|
||||
|
@ -78,9 +79,14 @@ class RoomUploadsMediaFragment @Inject constructor(
|
|||
controller.listener = this
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private fun getNumberOfColumns(): Int {
|
||||
val displayMetrics = DisplayMetrics()
|
||||
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
requireContext().display?.getMetrics(displayMetrics)
|
||||
} else {
|
||||
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
|
||||
}
|
||||
return dimensionConverter.pxToDp(displayMetrics.widthPixels) / IMAGE_SIZE_DP
|
||||
}
|
||||
|
||||
|
|
|
@ -64,7 +64,9 @@ class VectorWebViewActivity : VectorBaseActivity<ActivityVectorWebViewBinding>()
|
|||
// Allow use of Local Storage
|
||||
domStorageEnabled = true
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
allowFileAccessFromFileURLs = true
|
||||
@Suppress("DEPRECATION")
|
||||
allowUniversalAccessFromFileURLs = true
|
||||
|
||||
displayZoomControls = false
|
||||
|
@ -73,7 +75,7 @@ class VectorWebViewActivity : VectorBaseActivity<ActivityVectorWebViewBinding>()
|
|||
val cookieManager = android.webkit.CookieManager.getInstance()
|
||||
cookieManager.setAcceptThirdPartyCookies(views.simpleWebview, true)
|
||||
|
||||
val url = intent.extras?.getString(EXTRA_URL)
|
||||
val url = intent.extras?.getString(EXTRA_URL) ?: return
|
||||
val title = intent.extras?.getString(EXTRA_TITLE, USE_TITLE_FROM_WEB_PAGE)
|
||||
if (title != USE_TITLE_FROM_WEB_PAGE) {
|
||||
setTitle(title)
|
||||
|
|
|
@ -54,7 +54,9 @@ fun WebView.setupForWidget(webViewEventListener: WebViewEventListener) {
|
|||
// Allow use of Local Storage
|
||||
settings.domStorageEnabled = true
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
settings.allowFileAccessFromFileURLs = true
|
||||
@Suppress("DEPRECATION")
|
||||
settings.allowUniversalAccessFromFileURLs = true
|
||||
|
||||
settings.displayZoomControls = false
|
||||
|
@ -75,7 +77,6 @@ fun WebView.clearAfterWidget() {
|
|||
// Make sure you remove the WebView from its parent view before doing anything.
|
||||
(parent as? ViewGroup)?.removeAllViews()
|
||||
webChromeClient = null
|
||||
webViewClient = null
|
||||
clearHistory()
|
||||
// NOTE: clears RAM cache, if you pass true, it will also clear the disk cache.
|
||||
clearCache(true)
|
||||
|
|
Loading…
Reference in a new issue