mirror of
https://github.com/element-hq/element-android
synced 2024-11-27 20:06:51 +03:00
Merge pull request #3227 from vector-im/dependabot/gradle/kotlin_version-1.5.0
Bump kotlin_version from 1.4.32 to 1.5.0
This commit is contained in:
commit
1a70fa0fcc
46 changed files with 336 additions and 241 deletions
|
@ -17,6 +17,8 @@ SDK API changes ⚠️:
|
|||
-
|
||||
|
||||
Build 🧱:
|
||||
- Compile with Kotlin 1.5.
|
||||
- Upgrade some dependencies: gradle wrapper, third party lib, etc.
|
||||
- Sign APK with build tools 30.0.3
|
||||
|
||||
Test:
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
buildscript {
|
||||
// Ref: https://kotlinlang.org/releases.html
|
||||
ext.kotlin_version = '1.4.32'
|
||||
ext.kotlin_coroutines_version = "1.4.2"
|
||||
ext.kotlin_version = '1.5.0'
|
||||
ext.kotlin_coroutines_version = "1.5.0-RC"
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
|
@ -12,7 +12,7 @@ buildscript {
|
|||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.1.3'
|
||||
classpath 'com.android.tools.build:gradle:4.2.0'
|
||||
classpath 'com.google.gms:google-services:4.3.5'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.2.0'
|
||||
|
|
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,6 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=ca42877db3519b667cd531c414be517b294b0467059d401e7133f0e55b9bf265
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.1-all.zip
|
||||
distributionSha256Sum=13bf8d3cf8eeeb5770d19741a59bde9bd966dd78d17f1bbad787a05ef19d1c2d
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
@ -226,12 +226,12 @@ class QrCodeTest : InstrumentedTest {
|
|||
|
||||
private fun checkHeader(byteArray: ByteArray) {
|
||||
// MATRIX
|
||||
byteArray[0] shouldBeEqualTo 'M'.toByte()
|
||||
byteArray[1] shouldBeEqualTo 'A'.toByte()
|
||||
byteArray[2] shouldBeEqualTo 'T'.toByte()
|
||||
byteArray[3] shouldBeEqualTo 'R'.toByte()
|
||||
byteArray[4] shouldBeEqualTo 'I'.toByte()
|
||||
byteArray[5] shouldBeEqualTo 'X'.toByte()
|
||||
byteArray[0] shouldBeEqualTo 'M'.code.toByte()
|
||||
byteArray[1] shouldBeEqualTo 'A'.code.toByte()
|
||||
byteArray[2] shouldBeEqualTo 'T'.code.toByte()
|
||||
byteArray[3] shouldBeEqualTo 'R'.code.toByte()
|
||||
byteArray[4] shouldBeEqualTo 'I'.code.toByte()
|
||||
byteArray[5] shouldBeEqualTo 'X'.code.toByte()
|
||||
|
||||
// Version
|
||||
byteArray[6] shouldBeEqualTo 2
|
||||
|
|
|
@ -20,6 +20,7 @@ import android.annotation.SuppressLint
|
|||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import org.matrix.android.sdk.api.util.JsonDict
|
||||
import org.matrix.android.sdk.internal.util.safeCapitalize
|
||||
|
||||
/**
|
||||
* Ref: https://github.com/matrix-org/matrix-doc/issues/1236
|
||||
|
@ -39,6 +40,6 @@ data class WidgetContent(
|
|||
|
||||
@SuppressLint("DefaultLocale")
|
||||
fun getHumanName(): String {
|
||||
return (name ?: type ?: "").capitalize()
|
||||
return (name ?: type ?: "").safeCapitalize()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,22 +117,22 @@ sealed class MatrixItem(
|
|||
var first = dn[startIndex]
|
||||
|
||||
// LEFT-TO-RIGHT MARK
|
||||
if (dn.length >= 2 && 0x200e == first.toInt()) {
|
||||
if (dn.length >= 2 && 0x200e == first.code) {
|
||||
startIndex++
|
||||
first = dn[startIndex]
|
||||
}
|
||||
|
||||
// check if it’s the start of a surrogate pair
|
||||
if (first.toInt() in 0xD800..0xDBFF && dn.length > startIndex + 1) {
|
||||
if (first.code in 0xD800..0xDBFF && dn.length > startIndex + 1) {
|
||||
val second = dn[startIndex + 1]
|
||||
if (second.toInt() in 0xDC00..0xDFFF) {
|
||||
if (second.code in 0xDC00..0xDFFF) {
|
||||
length++
|
||||
}
|
||||
}
|
||||
|
||||
dn.substring(startIndex, startIndex + length)
|
||||
}
|
||||
.toUpperCase(Locale.ROOT)
|
||||
.uppercase(Locale.ROOT)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -345,7 +345,7 @@ internal abstract class SASDefaultVerificationTransaction(
|
|||
}
|
||||
|
||||
protected fun hashUsingAgreedHashMethod(toHash: String): String? {
|
||||
if ("sha256" == accepted?.hash?.toLowerCase(Locale.ROOT)) {
|
||||
if ("sha256" == accepted?.hash?.lowercase(Locale.ROOT)) {
|
||||
val olmUtil = OlmUtility()
|
||||
val hashBytes = olmUtil.sha256(toHash)
|
||||
olmUtil.releaseUtility()
|
||||
|
@ -355,7 +355,7 @@ internal abstract class SASDefaultVerificationTransaction(
|
|||
}
|
||||
|
||||
private fun macUsingAgreedMethod(message: String, info: String): String? {
|
||||
return when (accepted?.messageAuthenticationCode?.toLowerCase(Locale.ROOT)) {
|
||||
return when (accepted?.messageAuthenticationCode?.lowercase(Locale.ROOT)) {
|
||||
SAS_MAC_SHA256_LONGKDF -> getSAS().calculateMacLongKdf(message, info)
|
||||
SAS_MAC_SHA256 -> getSAS().calculateMac(message, info)
|
||||
else -> null
|
||||
|
|
|
@ -48,7 +48,7 @@ fun QrCodeData.toEncodedString(): String {
|
|||
|
||||
// TransactionId
|
||||
transactionId.forEach {
|
||||
result += it.toByte()
|
||||
result += it.code.toByte()
|
||||
}
|
||||
|
||||
// Keys
|
||||
|
|
|
@ -291,7 +291,7 @@ internal class DefaultFileService @Inject constructor(
|
|||
Timber.v("Get size of ${it.absolutePath}")
|
||||
true
|
||||
}
|
||||
.sumBy { it.length().toInt() }
|
||||
.sumOf { it.length().toInt() }
|
||||
}
|
||||
|
||||
override fun clearCache() {
|
||||
|
|
|
@ -117,7 +117,7 @@ internal class DefaultIdentityBulkLookupTask @Inject constructor(
|
|||
return withOlmUtility { olmUtility ->
|
||||
threePids.map { threePid ->
|
||||
base64ToBase64Url(
|
||||
olmUtility.sha256(threePid.value.toLowerCase(Locale.ROOT)
|
||||
olmUtility.sha256(threePid.value.lowercase(Locale.ROOT)
|
||||
+ " " + threePid.toMedium() + " " + pepper)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ fun String.md5() = try {
|
|||
digest.update(toByteArray())
|
||||
digest.digest()
|
||||
.joinToString("") { String.format("%02X", it) }
|
||||
.toLowerCase(Locale.ROOT)
|
||||
.lowercase(Locale.ROOT)
|
||||
} catch (exc: Exception) {
|
||||
// Should not happen, but just in case
|
||||
hashCode().toString()
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package org.matrix.android.sdk.internal.util
|
||||
|
||||
import timber.log.Timber
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* Convert a string to an UTF8 String
|
||||
|
@ -24,7 +25,7 @@ import timber.log.Timber
|
|||
* @param s the string to convert
|
||||
* @return the utf-8 string
|
||||
*/
|
||||
fun convertToUTF8(s: String): String {
|
||||
internal fun convertToUTF8(s: String): String {
|
||||
return try {
|
||||
val bytes = s.toByteArray(Charsets.UTF_8)
|
||||
String(bytes)
|
||||
|
@ -40,7 +41,7 @@ fun convertToUTF8(s: String): String {
|
|||
* @param s the string to convert
|
||||
* @return the utf-16 string
|
||||
*/
|
||||
fun convertFromUTF8(s: String): String {
|
||||
internal fun convertFromUTF8(s: String): String {
|
||||
return try {
|
||||
val bytes = s.toByteArray()
|
||||
String(bytes, Charsets.UTF_8)
|
||||
|
@ -56,7 +57,7 @@ fun convertFromUTF8(s: String): String {
|
|||
* @param subString the string to search for
|
||||
* @return whether a match was found
|
||||
*/
|
||||
fun String.caseInsensitiveFind(subString: String): Boolean {
|
||||
internal fun String.caseInsensitiveFind(subString: String): Boolean {
|
||||
// add sanity checks
|
||||
if (subString.isEmpty() || isEmpty()) {
|
||||
return false
|
||||
|
@ -78,3 +79,14 @@ internal val spaceChars = "[\u00A0\u2000-\u200B\u2800\u3000]".toRegex()
|
|||
* Strip all the UTF-8 chars which are actually spaces
|
||||
*/
|
||||
internal fun String.replaceSpaceChars() = replace(spaceChars, "")
|
||||
|
||||
// String.capitalize is now deprecated
|
||||
internal fun String.safeCapitalize(): String {
|
||||
return replaceFirstChar { char ->
|
||||
if (char.isLowerCase()) {
|
||||
char.titlecase(Locale.getDefault())
|
||||
} else {
|
||||
char.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,13 +19,14 @@ import android.content.Intent
|
|||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.di.ActiveSessionHolder
|
||||
import im.vector.app.core.error.ErrorFormatter
|
||||
import im.vector.app.core.pushers.PushersManager
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.session.coroutineScope
|
||||
import im.vector.app.features.settings.troubleshoot.TroubleshootTest
|
||||
import im.vector.app.push.fcm.FcmHelper
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
@ -38,7 +39,8 @@ import javax.inject.Inject
|
|||
class TestPushFromPushGateway @Inject constructor(private val context: AppCompatActivity,
|
||||
private val stringProvider: StringProvider,
|
||||
private val errorFormatter: ErrorFormatter,
|
||||
private val pushersManager: PushersManager)
|
||||
private val pushersManager: PushersManager,
|
||||
private val activeSessionHolder: ActiveSessionHolder)
|
||||
: TroubleshootTest(R.string.settings_troubleshoot_test_push_loop_title) {
|
||||
|
||||
private var action: Job? = null
|
||||
|
@ -50,7 +52,7 @@ class TestPushFromPushGateway @Inject constructor(private val context: AppCompat
|
|||
status = TestStatus.FAILED
|
||||
return
|
||||
}
|
||||
action = GlobalScope.launch {
|
||||
action = activeSessionHolder.getActiveSession().coroutineScope.launch {
|
||||
val result = runCatching { pushersManager.testPush(fcmToken) }
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
|
|
|
@ -22,10 +22,10 @@ import androidx.lifecycle.OnLifecycleEvent
|
|||
import arrow.core.Option
|
||||
import im.vector.app.core.di.ActiveSessionHolder
|
||||
import im.vector.app.core.utils.BehaviorDataSource
|
||||
import im.vector.app.features.session.coroutineScope
|
||||
import im.vector.app.features.ui.UiStateRepository
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
|
@ -63,30 +63,30 @@ class AppStateHandler @Inject constructor(
|
|||
fun getCurrentRoomGroupingMethod(): RoomGroupingMethod? = selectedSpaceDataSource.currentValue?.orNull()
|
||||
|
||||
fun setCurrentSpace(spaceId: String?, session: Session? = null) {
|
||||
val uSession = session ?: activeSessionHolder.getSafeActiveSession()
|
||||
val uSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return
|
||||
if (selectedSpaceDataSource.currentValue?.orNull() is RoomGroupingMethod.BySpace
|
||||
&& spaceId == selectedSpaceDataSource.currentValue?.orNull()?.space()?.roomId) return
|
||||
val spaceSum = spaceId?.let { uSession?.getRoomSummary(spaceId) }
|
||||
val spaceSum = spaceId?.let { uSession.getRoomSummary(spaceId) }
|
||||
selectedSpaceDataSource.post(Option.just(RoomGroupingMethod.BySpace(spaceSum)))
|
||||
if (spaceId != null) {
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
uSession.coroutineScope.launch(Dispatchers.IO) {
|
||||
tryOrNull {
|
||||
uSession?.getRoom(spaceId)?.loadRoomMembersIfNeeded()
|
||||
uSession.getRoom(spaceId)?.loadRoomMembersIfNeeded()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setCurrentGroup(groupId: String?, session: Session? = null) {
|
||||
val uSession = session ?: activeSessionHolder.getSafeActiveSession()
|
||||
val uSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return
|
||||
if (selectedSpaceDataSource.currentValue?.orNull() is RoomGroupingMethod.ByLegacyGroup
|
||||
&& groupId == selectedSpaceDataSource.currentValue?.orNull()?.group()?.groupId) return
|
||||
val activeGroup = groupId?.let { uSession?.getGroupSummary(groupId) }
|
||||
val activeGroup = groupId?.let { uSession.getGroupSummary(groupId) }
|
||||
selectedSpaceDataSource.post(Option.just(RoomGroupingMethod.ByLegacyGroup(activeGroup)))
|
||||
if (groupId != null) {
|
||||
GlobalScope.launch {
|
||||
uSession.coroutineScope.launch {
|
||||
tryOrNull {
|
||||
uSession?.getGroup(groupId)?.fetchGroupData()
|
||||
uSession.getGroup(groupId)?.fetchGroupData()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ fun getMimeTypeFromUri(context: Context, uri: Uri): String? {
|
|||
|
||||
if (null != mimeType) {
|
||||
// the mimetype is sometimes in uppercase.
|
||||
mimeType = mimeType.toLowerCase(Locale.ROOT)
|
||||
mimeType = mimeType.lowercase(Locale.ROOT)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Failed to open resource input stream")
|
||||
|
|
|
@ -42,13 +42,13 @@ fun CharSequence.splitEmoji(): List<CharSequence> {
|
|||
while (index < length) {
|
||||
val firstChar = get(index)
|
||||
|
||||
if (firstChar.toInt() == 0x200e) {
|
||||
if (firstChar.code == 0x200e) {
|
||||
// Left to right mark. What should I do with it?
|
||||
} else if (firstChar.toInt() in 0xD800..0xDBFF && index + 1 < length) {
|
||||
} else if (firstChar.code in 0xD800..0xDBFF && index + 1 < length) {
|
||||
// We have the start of a surrogate pair
|
||||
val secondChar = get(index + 1)
|
||||
|
||||
if (secondChar.toInt() in 0xDC00..0xDFFF) {
|
||||
if (secondChar.code in 0xDC00..0xDFFF) {
|
||||
// We have an emoji
|
||||
result.add("$firstChar$secondChar")
|
||||
index++
|
||||
|
|
|
@ -43,8 +43,7 @@ import im.vector.app.R
|
|||
import im.vector.app.features.notifications.NotificationUtils
|
||||
import im.vector.app.features.themes.ThemeUtils
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import okio.buffer
|
||||
import okio.sink
|
||||
import okio.source
|
||||
|
@ -57,6 +56,7 @@ import timber.log.Timber
|
|||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
import java.lang.IllegalStateException
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
@ -344,90 +344,93 @@ private fun appendTimeToFilename(name: String): String {
|
|||
return """${filename}_$dateExtension.$fileExtension"""
|
||||
}
|
||||
|
||||
fun saveMedia(context: Context, file: File, title: String, mediaMimeType: String?, notificationUtils: NotificationUtils) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
val filename = appendTimeToFilename(title)
|
||||
suspend fun saveMedia(context: Context, file: File, title: String, mediaMimeType: String?, notificationUtils: NotificationUtils) {
|
||||
withContext(Dispatchers.IO) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
val filename = appendTimeToFilename(title)
|
||||
|
||||
val values = ContentValues().apply {
|
||||
put(MediaStore.Images.Media.TITLE, filename)
|
||||
put(MediaStore.Images.Media.DISPLAY_NAME, filename)
|
||||
put(MediaStore.Images.Media.MIME_TYPE, mediaMimeType)
|
||||
put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis())
|
||||
put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis())
|
||||
}
|
||||
val externalContentUri = when {
|
||||
mediaMimeType?.isMimeTypeImage() == true -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI
|
||||
mediaMimeType?.isMimeTypeVideo() == true -> MediaStore.Video.Media.EXTERNAL_CONTENT_URI
|
||||
mediaMimeType?.isMimeTypeAudio() == true -> MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
|
||||
else -> MediaStore.Downloads.EXTERNAL_CONTENT_URI
|
||||
}
|
||||
val values = ContentValues().apply {
|
||||
put(MediaStore.Images.Media.TITLE, filename)
|
||||
put(MediaStore.Images.Media.DISPLAY_NAME, filename)
|
||||
put(MediaStore.Images.Media.MIME_TYPE, mediaMimeType)
|
||||
put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis())
|
||||
put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis())
|
||||
}
|
||||
val externalContentUri = when {
|
||||
mediaMimeType?.isMimeTypeImage() == true -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI
|
||||
mediaMimeType?.isMimeTypeVideo() == true -> MediaStore.Video.Media.EXTERNAL_CONTENT_URI
|
||||
mediaMimeType?.isMimeTypeAudio() == true -> MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
|
||||
else -> MediaStore.Downloads.EXTERNAL_CONTENT_URI
|
||||
}
|
||||
|
||||
val uri = context.contentResolver.insert(externalContentUri, values)
|
||||
if (uri == null) {
|
||||
Toast.makeText(context, R.string.error_saving_media_file, Toast.LENGTH_LONG).show()
|
||||
} else {
|
||||
val source = file.inputStream().source().buffer()
|
||||
context.contentResolver.openOutputStream(uri)?.sink()?.buffer()?.let { sink ->
|
||||
source.use { input ->
|
||||
sink.use { output ->
|
||||
output.writeAll(input)
|
||||
val uri = context.contentResolver.insert(externalContentUri, values)
|
||||
if (uri == null) {
|
||||
Toast.makeText(context, R.string.error_saving_media_file, Toast.LENGTH_LONG).show()
|
||||
throw IllegalStateException(context.getString(R.string.error_saving_media_file))
|
||||
} else {
|
||||
val source = file.inputStream().source().buffer()
|
||||
context.contentResolver.openOutputStream(uri)?.sink()?.buffer()?.let { sink ->
|
||||
source.use { input ->
|
||||
sink.use { output ->
|
||||
output.writeAll(input)
|
||||
}
|
||||
}
|
||||
}
|
||||
notificationUtils.buildDownloadFileNotification(
|
||||
uri,
|
||||
filename,
|
||||
mediaMimeType ?: MimeTypes.OctetStream
|
||||
).let { notification ->
|
||||
notificationUtils.showNotificationMessage("DL", uri.hashCode(), notification)
|
||||
}
|
||||
}
|
||||
notificationUtils.buildDownloadFileNotification(
|
||||
uri,
|
||||
filename,
|
||||
mediaMimeType ?: MimeTypes.OctetStream
|
||||
).let { notification ->
|
||||
notificationUtils.showNotificationMessage("DL", uri.hashCode(), notification)
|
||||
}
|
||||
} else {
|
||||
saveMediaLegacy(context, mediaMimeType, title, file)
|
||||
}
|
||||
} else {
|
||||
saveMediaLegacy(context, mediaMimeType, title, file)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private fun saveMediaLegacy(context: Context, mediaMimeType: String?, title: String, file: File) {
|
||||
private fun saveMediaLegacy(context: Context,
|
||||
mediaMimeType: String?,
|
||||
title: String,
|
||||
file: File) {
|
||||
val state = Environment.getExternalStorageState()
|
||||
if (Environment.MEDIA_MOUNTED != state) {
|
||||
context.toast(context.getString(R.string.error_saving_media_file))
|
||||
return
|
||||
throw IllegalStateException(context.getString(R.string.error_saving_media_file))
|
||||
}
|
||||
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
val dest = when {
|
||||
mediaMimeType?.isMimeTypeImage() == true -> Environment.DIRECTORY_PICTURES
|
||||
mediaMimeType?.isMimeTypeVideo() == true -> Environment.DIRECTORY_MOVIES
|
||||
mediaMimeType?.isMimeTypeAudio() == true -> Environment.DIRECTORY_MUSIC
|
||||
else -> Environment.DIRECTORY_DOWNLOADS
|
||||
val dest = when {
|
||||
mediaMimeType?.isMimeTypeImage() == true -> Environment.DIRECTORY_PICTURES
|
||||
mediaMimeType?.isMimeTypeVideo() == true -> Environment.DIRECTORY_MOVIES
|
||||
mediaMimeType?.isMimeTypeAudio() == true -> Environment.DIRECTORY_MUSIC
|
||||
else -> Environment.DIRECTORY_DOWNLOADS
|
||||
}
|
||||
val downloadDir = Environment.getExternalStoragePublicDirectory(dest)
|
||||
try {
|
||||
val outputFilename = if (title.substringAfterLast('.', "").isEmpty()) {
|
||||
val extension = mediaMimeType?.let { MimeTypeMap.getSingleton().getExtensionFromMimeType(it) }
|
||||
"$title.$extension"
|
||||
} else {
|
||||
title
|
||||
}
|
||||
val downloadDir = Environment.getExternalStoragePublicDirectory(dest)
|
||||
try {
|
||||
val outputFilename = if (title.substringAfterLast('.', "").isEmpty()) {
|
||||
val extension = mediaMimeType?.let { MimeTypeMap.getSingleton().getExtensionFromMimeType(it) }
|
||||
"$title.$extension"
|
||||
} else {
|
||||
title
|
||||
}
|
||||
val savedFile = saveFileIntoLegacy(file, downloadDir, outputFilename)
|
||||
if (savedFile != null) {
|
||||
val downloadManager = context.getSystemService<DownloadManager>()
|
||||
downloadManager?.addCompletedDownload(
|
||||
savedFile.name,
|
||||
title,
|
||||
true,
|
||||
mediaMimeType ?: MimeTypes.OctetStream,
|
||||
savedFile.absolutePath,
|
||||
savedFile.length(),
|
||||
true)
|
||||
addToGallery(savedFile, mediaMimeType, context)
|
||||
}
|
||||
} catch (error: Throwable) {
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
context.toast(context.getString(R.string.error_saving_media_file))
|
||||
}
|
||||
val savedFile = saveFileIntoLegacy(file, downloadDir, outputFilename)
|
||||
if (savedFile != null) {
|
||||
val downloadManager = context.getSystemService<DownloadManager>()
|
||||
downloadManager?.addCompletedDownload(
|
||||
savedFile.name,
|
||||
title,
|
||||
true,
|
||||
mediaMimeType ?: MimeTypes.OctetStream,
|
||||
savedFile.absolutePath,
|
||||
savedFile.length(),
|
||||
true)
|
||||
addToGallery(savedFile, mediaMimeType, context)
|
||||
}
|
||||
} catch (error: Throwable) {
|
||||
context.toast(context.getString(R.string.error_saving_media_file))
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ fun getFileExtension(fileUri: String): String? {
|
|||
val ext = filename.substring(dotPos + 1)
|
||||
|
||||
if (ext.isNotBlank()) {
|
||||
return ext.toLowerCase(Locale.ROOT)
|
||||
return ext.lowercase(Locale.ROOT)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -131,5 +131,5 @@ fun getSizeOfFiles(root: File): Int {
|
|||
Timber.v("Get size of ${it.absolutePath}")
|
||||
true
|
||||
}
|
||||
.sumBy { it.length().toInt() }
|
||||
.sumOf { it.length().toInt() }
|
||||
}
|
||||
|
|
30
vector/src/main/java/im/vector/app/core/utils/StringUtils.kt
Normal file
30
vector/src/main/java/im/vector/app/core/utils/StringUtils.kt
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2021 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.app.core.utils
|
||||
|
||||
import java.util.Locale
|
||||
|
||||
// String.capitalize is now deprecated
|
||||
fun String.safeCapitalize(locale: Locale): String {
|
||||
return replaceFirstChar { char ->
|
||||
if (char.isLowerCase()) {
|
||||
char.titlecase(locale)
|
||||
} else {
|
||||
char.toString()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,11 +33,12 @@ import im.vector.app.features.call.utils.awaitCreateOffer
|
|||
import im.vector.app.features.call.utils.awaitSetLocalDescription
|
||||
import im.vector.app.features.call.utils.awaitSetRemoteDescription
|
||||
import im.vector.app.features.call.utils.mapToCallCandidate
|
||||
import im.vector.app.features.session.coroutineScope
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.subjects.PublishSubject
|
||||
import io.reactivex.subjects.ReplaySubject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
@ -103,6 +104,9 @@ class WebRtcCall(val mxCall: MxCall,
|
|||
|
||||
private val listeners = CopyOnWriteArrayList<Listener>()
|
||||
|
||||
private val sessionScope: CoroutineScope?
|
||||
get() = sessionProvider.get()?.coroutineScope
|
||||
|
||||
fun addListener(listener: Listener) {
|
||||
listeners.add(listener)
|
||||
}
|
||||
|
@ -191,7 +195,7 @@ class WebRtcCall(val mxCall: MxCall,
|
|||
fun onIceCandidate(iceCandidate: IceCandidate) = iceCandidateSource.onNext(iceCandidate)
|
||||
|
||||
fun onRenegotiationNeeded(restartIce: Boolean) {
|
||||
GlobalScope.launch(dispatcher) {
|
||||
sessionScope?.launch(dispatcher) {
|
||||
if (mxCall.state != CallState.CreateOffer && mxCall.opponentVersion == 0) {
|
||||
Timber.v("Opponent does not support renegotiation: ignoring onRenegotiationNeeded event")
|
||||
return@launch
|
||||
|
@ -262,7 +266,7 @@ class WebRtcCall(val mxCall: MxCall,
|
|||
localSurfaceRenderers.addIfNeeded(localViewRenderer)
|
||||
remoteSurfaceRenderers.addIfNeeded(remoteViewRenderer)
|
||||
|
||||
GlobalScope.launch(dispatcher) {
|
||||
sessionScope?.launch(dispatcher) {
|
||||
when (mode) {
|
||||
VectorCallActivity.INCOMING_ACCEPT -> {
|
||||
internalAcceptIncomingCall()
|
||||
|
@ -283,7 +287,7 @@ class WebRtcCall(val mxCall: MxCall,
|
|||
}
|
||||
|
||||
fun acceptIncomingCall() {
|
||||
GlobalScope.launch {
|
||||
sessionScope?.launch {
|
||||
Timber.v("## VOIP acceptIncomingCall from state ${mxCall.state}")
|
||||
if (mxCall.state == CallState.LocalRinging) {
|
||||
internalAcceptIncomingCall()
|
||||
|
@ -564,7 +568,7 @@ class WebRtcCall(val mxCall: MxCall,
|
|||
}
|
||||
|
||||
fun updateRemoteOnHold(onHold: Boolean) {
|
||||
GlobalScope.launch(dispatcher) {
|
||||
sessionScope?.launch(dispatcher) {
|
||||
if (remoteOnHold == onHold) return@launch
|
||||
val direction: RtpTransceiver.RtpTransceiverDirection
|
||||
if (onHold) {
|
||||
|
@ -688,7 +692,7 @@ class WebRtcCall(val mxCall: MxCall,
|
|||
}
|
||||
|
||||
fun onAddStream(stream: MediaStream) {
|
||||
GlobalScope.launch(dispatcher) {
|
||||
sessionScope?.launch(dispatcher) {
|
||||
// reportError("Weird-looking stream: " + stream);
|
||||
if (stream.audioTracks.size > 1 || stream.videoTracks.size > 1) {
|
||||
Timber.e("## VOIP StreamObserver weird looking stream: $stream")
|
||||
|
@ -712,7 +716,7 @@ class WebRtcCall(val mxCall: MxCall,
|
|||
}
|
||||
|
||||
fun onRemoveStream() {
|
||||
GlobalScope.launch(dispatcher) {
|
||||
sessionScope?.launch(dispatcher) {
|
||||
remoteSurfaceRenderers
|
||||
.mapNotNull { it.get() }
|
||||
.forEach { remoteVideoTrack?.removeSink(it) }
|
||||
|
@ -734,7 +738,7 @@ class WebRtcCall(val mxCall: MxCall,
|
|||
}
|
||||
val wasRinging = mxCall.state is CallState.LocalRinging
|
||||
mxCall.state = CallState.Terminated
|
||||
GlobalScope.launch(dispatcher) {
|
||||
sessionScope?.launch(dispatcher) {
|
||||
release()
|
||||
}
|
||||
onCallEnded(callId)
|
||||
|
@ -750,7 +754,7 @@ class WebRtcCall(val mxCall: MxCall,
|
|||
// Call listener
|
||||
|
||||
fun onCallIceCandidateReceived(iceCandidatesContent: CallCandidatesContent) {
|
||||
GlobalScope.launch(dispatcher) {
|
||||
sessionScope?.launch(dispatcher) {
|
||||
iceCandidatesContent.candidates.forEach {
|
||||
if (it.sdpMid.isNullOrEmpty() || it.candidate.isNullOrEmpty()) {
|
||||
return@forEach
|
||||
|
@ -763,7 +767,7 @@ class WebRtcCall(val mxCall: MxCall,
|
|||
}
|
||||
|
||||
fun onCallAnswerReceived(callAnswerContent: CallAnswerContent) {
|
||||
GlobalScope.launch(dispatcher) {
|
||||
sessionScope?.launch(dispatcher) {
|
||||
Timber.v("## VOIP onCallAnswerReceived ${callAnswerContent.callId}")
|
||||
val sdp = SessionDescription(SessionDescription.Type.ANSWER, callAnswerContent.answer.sdp)
|
||||
try {
|
||||
|
@ -779,7 +783,7 @@ class WebRtcCall(val mxCall: MxCall,
|
|||
}
|
||||
|
||||
fun onCallNegotiateReceived(callNegotiateContent: CallNegotiateContent) {
|
||||
GlobalScope.launch(dispatcher) {
|
||||
sessionScope?.launch(dispatcher) {
|
||||
val description = callNegotiateContent.description
|
||||
val type = description?.type
|
||||
val sdpText = description?.sdp
|
||||
|
|
|
@ -18,8 +18,8 @@ package im.vector.app.features.crypto.keys
|
|||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import im.vector.app.features.session.coroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.matrix.android.sdk.api.MatrixCallback
|
||||
|
@ -33,7 +33,7 @@ class KeysExporter(private val session: Session) {
|
|||
* Export keys and return the file path with the callback
|
||||
*/
|
||||
fun export(context: Context, password: String, uri: Uri, callback: MatrixCallback<Boolean>) {
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
session.coroutineScope.launch(Dispatchers.Main) {
|
||||
runCatching {
|
||||
withContext(Dispatchers.IO) {
|
||||
val data = awaitCallback<ByteArray> { session.cryptoService().exportRoomKeys(password, it) }
|
||||
|
|
|
@ -20,8 +20,8 @@ import android.content.Context
|
|||
import android.net.Uri
|
||||
import im.vector.app.core.intent.getMimeTypeFromUri
|
||||
import im.vector.app.core.resources.openResource
|
||||
import im.vector.app.features.session.coroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.matrix.android.sdk.api.MatrixCallback
|
||||
|
@ -41,7 +41,7 @@ class KeysImporter(private val session: Session) {
|
|||
mimetype: String?,
|
||||
password: String,
|
||||
callback: MatrixCallback<ImportRoomKeysResult>) {
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
session.coroutineScope.launch(Dispatchers.Main) {
|
||||
runCatching {
|
||||
withContext(Dispatchers.IO) {
|
||||
val resource = openResource(context, uri, mimetype ?: getMimeTypeFromUri(context, uri))
|
||||
|
|
|
@ -25,6 +25,7 @@ import android.widget.TextView
|
|||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import arrow.core.Try
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import im.vector.app.R
|
||||
|
@ -37,7 +38,6 @@ import im.vector.app.core.utils.startSharePlainTextIntent
|
|||
import im.vector.app.databinding.FragmentKeysBackupSetupStep3Binding
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.IOException
|
||||
|
@ -163,7 +163,7 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment<Fr
|
|||
}
|
||||
|
||||
private fun exportRecoveryKeyToFile(uri: Uri, data: String) {
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
lifecycleScope.launch(Dispatchers.Main) {
|
||||
Try {
|
||||
withContext(Dispatchers.IO) {
|
||||
requireContext().contentResolver.openOutputStream(uri)
|
||||
|
|
|
@ -24,6 +24,7 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.app.R
|
||||
|
@ -35,7 +36,6 @@ import im.vector.app.core.utils.toast
|
|||
import im.vector.app.databinding.FragmentBootstrapSaveKeyBinding
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -80,7 +80,7 @@ class BootstrapSaveRecoveryKeyFragment @Inject constructor(
|
|||
private val saveStartForActivityResult = registerStartForActivityResult { activityResult ->
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
val uri = activityResult.data?.data ?: return@registerStartForActivityResult
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
sharedViewModel.handle(BootstrapActions.SaveKeyToUri(requireContext().contentResolver!!.openOutputStream(uri)!!))
|
||||
} catch (failure: Throwable) {
|
||||
|
|
|
@ -33,7 +33,6 @@ import im.vector.app.core.extensions.exhaustive
|
|||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.MatrixCallback
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
|
@ -427,7 +426,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
|
|||
}
|
||||
|
||||
private fun tentativeRestoreBackup(res: Map<String, String>?) {
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val secret = res?.get(KEYBACKUP_SECRET_SSSS_NAME) ?: return@launch Unit.also {
|
||||
Timber.v("## Keybackup secret not restored from SSSS")
|
||||
|
|
|
@ -27,9 +27,9 @@ import im.vector.app.core.di.ActiveSessionHolder
|
|||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.features.login.ReAuthHelper
|
||||
import im.vector.app.features.session.coroutineScope
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.auth.UIABaseAuth
|
||||
|
@ -184,7 +184,7 @@ class HomeActivityViewModel @AssistedInject constructor(
|
|||
|
||||
private fun maybeBootstrapCrossSigningAfterInitialSync() {
|
||||
// We do not use the viewModel context because we do not want to tie this action to activity view model
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
activeSessionHolder.getSafeActiveSession()?.coroutineScope?.launch(Dispatchers.IO) {
|
||||
val session = activeSessionHolder.getSafeActiveSession() ?: return@launch
|
||||
|
||||
tryOrNull("## MaybeBootstrapCrossSigning: Failed to download keys") {
|
||||
|
|
|
@ -1745,20 +1745,19 @@ class RoomDetailFragment @Inject constructor(
|
|||
session.coroutineScope.launch {
|
||||
val result = runCatching { session.fileService().downloadFile(messageContent = action.messageContent) }
|
||||
if (!isAdded) return@launch
|
||||
result.fold(
|
||||
{
|
||||
saveMedia(
|
||||
context = requireContext(),
|
||||
file = it,
|
||||
title = action.messageContent.body,
|
||||
mediaMimeType = action.messageContent.mimeType ?: getMimeTypeFromUri(requireContext(), it.toUri()),
|
||||
notificationUtils = notificationUtils
|
||||
)
|
||||
},
|
||||
{
|
||||
result.mapCatching {
|
||||
saveMedia(
|
||||
context = requireContext(),
|
||||
file = it,
|
||||
title = action.messageContent.body,
|
||||
mediaMimeType = action.messageContent.mimeType ?: getMimeTypeFromUri(requireContext(), it.toUri()),
|
||||
notificationUtils = notificationUtils
|
||||
)
|
||||
}
|
||||
.onFailure {
|
||||
if (!isAdded) return@onFailure
|
||||
showErrorInSnackbar(it)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -449,7 +449,7 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||
widgetSessionId = widgetSessionId.substring(0, 7)
|
||||
}
|
||||
val roomId: String = room.roomId
|
||||
val confId = roomId.substring(1, roomId.indexOf(":") - 1) + widgetSessionId.toLowerCase(VectorLocale.applicationLocale)
|
||||
val confId = roomId.substring(1, roomId.indexOf(":") - 1) + widgetSessionId.lowercase(VectorLocale.applicationLocale)
|
||||
|
||||
val preferredJitsiDomain = tryOrNull {
|
||||
rawService.getElementWellknown(session.myUserId)
|
||||
|
|
|
@ -50,7 +50,7 @@ class MatrixItemColorProvider @Inject constructor(
|
|||
fun getColorFromUserId(userId: String?): Int {
|
||||
var hash = 0
|
||||
|
||||
userId?.toList()?.map { chr -> hash = (hash shl 5) - hash + chr.toInt() }
|
||||
userId?.toList()?.map { chr -> hash = (hash shl 5) - hash + chr.code }
|
||||
|
||||
return when (abs(hash) % 8) {
|
||||
1 -> R.color.riotx_username_2
|
||||
|
@ -66,7 +66,7 @@ class MatrixItemColorProvider @Inject constructor(
|
|||
|
||||
@ColorRes
|
||||
private fun getColorFromRoomId(roomId: String?): Int {
|
||||
return when ((roomId?.toList()?.sumBy { it.toInt() } ?: 0) % 3) {
|
||||
return when ((roomId?.toList()?.sumOf { it.code } ?: 0) % 3) {
|
||||
1 -> R.color.riotx_avatar_fill_2
|
||||
2 -> R.color.riotx_avatar_fill_3
|
||||
else -> R.color.riotx_avatar_fill_1
|
||||
|
|
|
@ -18,6 +18,7 @@ package im.vector.app.features.media
|
|||
|
||||
import im.vector.app.core.date.VectorDateFormatter
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.room.Room
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
|
@ -30,24 +31,31 @@ class AttachmentProviderFactory @Inject constructor(
|
|||
private val session: Session
|
||||
) {
|
||||
|
||||
fun createProvider(attachments: List<TimelineEvent>): RoomEventsAttachmentProvider {
|
||||
fun createProvider(attachments: List<TimelineEvent>,
|
||||
coroutineScope: CoroutineScope
|
||||
): RoomEventsAttachmentProvider {
|
||||
return RoomEventsAttachmentProvider(
|
||||
attachments,
|
||||
imageContentRenderer,
|
||||
vectorDateFormatter,
|
||||
session.fileService(),
|
||||
stringProvider
|
||||
attachments = attachments,
|
||||
imageContentRenderer = imageContentRenderer,
|
||||
dateFormatter = vectorDateFormatter,
|
||||
fileService = session.fileService(),
|
||||
coroutineScope = coroutineScope,
|
||||
stringProvider = stringProvider
|
||||
)
|
||||
}
|
||||
|
||||
fun createProvider(attachments: List<AttachmentData>, room: Room?): DataAttachmentRoomProvider {
|
||||
fun createProvider(attachments: List<AttachmentData>,
|
||||
room: Room?,
|
||||
coroutineScope: CoroutineScope
|
||||
): DataAttachmentRoomProvider {
|
||||
return DataAttachmentRoomProvider(
|
||||
attachments,
|
||||
room,
|
||||
imageContentRenderer,
|
||||
vectorDateFormatter,
|
||||
session.fileService(),
|
||||
stringProvider
|
||||
attachments = attachments,
|
||||
room = room,
|
||||
imageContentRenderer = imageContentRenderer,
|
||||
dateFormatter = vectorDateFormatter,
|
||||
fileService = session.fileService(),
|
||||
coroutineScope = coroutineScope,
|
||||
stringProvider = stringProvider
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,8 +31,8 @@ import im.vector.lib.attachmentviewer.AttachmentInfo
|
|||
import im.vector.lib.attachmentviewer.AttachmentSourceProvider
|
||||
import im.vector.lib.attachmentviewer.ImageLoaderTarget
|
||||
import im.vector.lib.attachmentviewer.VideoLoaderTarget
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.matrix.android.sdk.api.session.events.model.isVideoMessage
|
||||
|
@ -44,6 +44,7 @@ abstract class BaseAttachmentProvider<Type>(
|
|||
private val attachments: List<Type>,
|
||||
private val imageContentRenderer: ImageContentRenderer,
|
||||
protected val fileService: FileService,
|
||||
private val coroutineScope: CoroutineScope,
|
||||
private val dateFormatter: VectorDateFormatter,
|
||||
private val stringProvider: StringProvider
|
||||
) : AttachmentSourceProvider {
|
||||
|
@ -155,7 +156,7 @@ abstract class BaseAttachmentProvider<Type>(
|
|||
target.onVideoURLReady(info.uid, data.url)
|
||||
} else {
|
||||
target.onVideoFileLoading(info.uid)
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
coroutineScope.launch(Dispatchers.IO) {
|
||||
val result = runCatching {
|
||||
fileService.downloadFile(
|
||||
fileName = data.filename,
|
||||
|
@ -178,5 +179,5 @@ abstract class BaseAttachmentProvider<Type>(
|
|||
// TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
abstract fun getFileForSharing(position: Int, callback: ((File?) -> Unit))
|
||||
abstract suspend fun getFileForSharing(position: Int): File?
|
||||
}
|
||||
|
|
|
@ -19,10 +19,8 @@ package im.vector.app.features.media
|
|||
import im.vector.app.core.date.VectorDateFormatter
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.lib.attachmentviewer.AttachmentInfo
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.session.file.FileService
|
||||
import org.matrix.android.sdk.api.session.room.Room
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
|
@ -35,8 +33,16 @@ class DataAttachmentRoomProvider(
|
|||
imageContentRenderer: ImageContentRenderer,
|
||||
dateFormatter: VectorDateFormatter,
|
||||
fileService: FileService,
|
||||
coroutineScope: CoroutineScope,
|
||||
stringProvider: StringProvider
|
||||
) : BaseAttachmentProvider<AttachmentData>(attachments, imageContentRenderer, fileService, dateFormatter, stringProvider) {
|
||||
) : BaseAttachmentProvider<AttachmentData>(
|
||||
attachments = attachments,
|
||||
imageContentRenderer = imageContentRenderer,
|
||||
fileService = fileService,
|
||||
coroutineScope = coroutineScope,
|
||||
dateFormatter = dateFormatter,
|
||||
stringProvider = stringProvider
|
||||
) {
|
||||
|
||||
override fun getAttachmentInfoAt(position: Int): AttachmentInfo {
|
||||
return getItem(position).let {
|
||||
|
@ -78,20 +84,17 @@ class DataAttachmentRoomProvider(
|
|||
return room?.getTimeLineEvent(item.eventId)
|
||||
}
|
||||
|
||||
override fun getFileForSharing(position: Int, callback: (File?) -> Unit) {
|
||||
val item = getItem(position)
|
||||
GlobalScope.launch {
|
||||
val result = runCatching {
|
||||
fileService.downloadFile(
|
||||
fileName = item.filename,
|
||||
mimeType = item.mimeType,
|
||||
url = item.url,
|
||||
elementToDecrypt = item.elementToDecrypt
|
||||
)
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
callback(result.getOrNull())
|
||||
}
|
||||
}
|
||||
override suspend fun getFileForSharing(position: Int): File? {
|
||||
return getItem(position)
|
||||
.let { item ->
|
||||
tryOrNull {
|
||||
fileService.downloadFile(
|
||||
fileName = item.filename,
|
||||
mimeType = item.mimeType,
|
||||
url = item.url,
|
||||
elementToDecrypt = item.elementToDecrypt
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,10 +19,8 @@ package im.vector.app.features.media
|
|||
import im.vector.app.core.date.VectorDateFormatter
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.lib.attachmentviewer.AttachmentInfo
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.file.FileService
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
|
||||
|
@ -41,8 +39,16 @@ class RoomEventsAttachmentProvider(
|
|||
imageContentRenderer: ImageContentRenderer,
|
||||
dateFormatter: VectorDateFormatter,
|
||||
fileService: FileService,
|
||||
coroutineScope: CoroutineScope,
|
||||
stringProvider: StringProvider
|
||||
) : BaseAttachmentProvider<TimelineEvent>(attachments, imageContentRenderer, fileService, dateFormatter, stringProvider) {
|
||||
) : BaseAttachmentProvider<TimelineEvent>(
|
||||
attachments = attachments,
|
||||
imageContentRenderer = imageContentRenderer,
|
||||
fileService = fileService,
|
||||
coroutineScope = coroutineScope,
|
||||
dateFormatter = dateFormatter,
|
||||
stringProvider = stringProvider
|
||||
) {
|
||||
|
||||
override fun getAttachmentInfoAt(position: Int): AttachmentInfo {
|
||||
return getItem(position).let {
|
||||
|
@ -121,24 +127,19 @@ class RoomEventsAttachmentProvider(
|
|||
return getItem(position)
|
||||
}
|
||||
|
||||
override fun getFileForSharing(position: Int, callback: (File?) -> Unit) {
|
||||
getItem(position).let { timelineEvent ->
|
||||
|
||||
val messageContent = timelineEvent.root.getClearContent().toModel<MessageContent>()
|
||||
as? MessageWithAttachmentContent
|
||||
?: return@let
|
||||
GlobalScope.launch {
|
||||
val result = runCatching {
|
||||
fileService.downloadFile(
|
||||
fileName = messageContent.body,
|
||||
mimeType = messageContent.mimeType,
|
||||
url = messageContent.getFileUrl(),
|
||||
elementToDecrypt = messageContent.encryptedFileInfo?.toElementToDecrypt())
|
||||
override suspend fun getFileForSharing(position: Int): File? {
|
||||
return getItem(position)
|
||||
.let { timelineEvent ->
|
||||
timelineEvent.root.getClearContent().toModel<MessageContent>() as? MessageWithAttachmentContent
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
callback(result.getOrNull())
|
||||
?.let { messageContent ->
|
||||
tryOrNull {
|
||||
fileService.downloadFile(
|
||||
fileName = messageContent.body,
|
||||
mimeType = messageContent.mimeType,
|
||||
url = messageContent.getFileUrl(),
|
||||
elementToDecrypt = messageContent.encryptedFileInfo?.toElementToDecrypt())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ import androidx.core.transition.addListener
|
|||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.transition.Transition
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.di.ActiveSessionHolder
|
||||
|
@ -42,6 +42,9 @@ import im.vector.app.features.themes.ActivityOtherThemes
|
|||
import im.vector.app.features.themes.ThemeUtils
|
||||
import im.vector.lib.attachmentviewer.AttachmentCommands
|
||||
import im.vector.lib.attachmentviewer.AttachmentViewerActivity
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
@ -119,11 +122,11 @@ class VectorAttachmentViewerActivity : AttachmentViewerActivity(), BaseAttachmen
|
|||
val inMemoryData = intent.getParcelableArrayListExtra<AttachmentData>(EXTRA_IN_MEMORY_DATA)
|
||||
val sourceProvider = if (inMemoryData != null) {
|
||||
initialIndex = inMemoryData.indexOfFirst { it.eventId == args.eventId }.coerceAtLeast(0)
|
||||
dataSourceFactory.createProvider(inMemoryData, room)
|
||||
dataSourceFactory.createProvider(inMemoryData, room, lifecycleScope)
|
||||
} else {
|
||||
val events = room?.getAttachmentMessages().orEmpty()
|
||||
initialIndex = events.indexOfFirst { it.eventId == args.eventId }.coerceAtLeast(0)
|
||||
dataSourceFactory.createProvider(events)
|
||||
dataSourceFactory.createProvider(events, lifecycleScope)
|
||||
}
|
||||
sourceProvider.interactionListener = this
|
||||
setSourceProvider(sourceProvider)
|
||||
|
@ -264,9 +267,15 @@ class VectorAttachmentViewerActivity : AttachmentViewerActivity(), BaseAttachmen
|
|||
}
|
||||
|
||||
override fun onShareTapped() {
|
||||
currentSourceProvider?.getFileForSharing(currentPosition) { data ->
|
||||
if (data != null && lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) {
|
||||
shareMedia(this@VectorAttachmentViewerActivity, data, getMimeTypeFromUri(this@VectorAttachmentViewerActivity, data.toUri()))
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val file = currentSourceProvider?.getFileForSharing(currentPosition) ?: return@launch
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
shareMedia(
|
||||
this@VectorAttachmentViewerActivity,
|
||||
file,
|
||||
getMimeTypeFromUri(this@VectorAttachmentViewerActivity, file.toUri())
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,8 +25,9 @@ import im.vector.app.R
|
|||
import im.vector.app.core.di.ActiveSessionHolder
|
||||
import im.vector.app.core.error.ErrorFormatter
|
||||
import im.vector.app.core.files.LocalFilesHelper
|
||||
import im.vector.app.features.session.coroutineScope
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
@ -39,6 +40,9 @@ class VideoContentRenderer @Inject constructor(private val localFilesHelper: Loc
|
|||
private val activeSessionHolder: ActiveSessionHolder,
|
||||
private val errorFormatter: ErrorFormatter) {
|
||||
|
||||
private val sessionScope: CoroutineScope
|
||||
get() = activeSessionHolder.getActiveSession().coroutineScope
|
||||
|
||||
@Parcelize
|
||||
data class Data(
|
||||
override val eventId: String,
|
||||
|
@ -76,7 +80,7 @@ class VideoContentRenderer @Inject constructor(private val localFilesHelper: Loc
|
|||
thumbnailView.isVisible = true
|
||||
loadingView.isVisible = true
|
||||
|
||||
GlobalScope.launch {
|
||||
sessionScope.launch {
|
||||
val result = runCatching {
|
||||
activeSessionHolder.getActiveSession().fileService()
|
||||
.downloadFile(
|
||||
|
@ -119,7 +123,7 @@ class VideoContentRenderer @Inject constructor(private val localFilesHelper: Loc
|
|||
thumbnailView.isVisible = true
|
||||
loadingView.isVisible = true
|
||||
|
||||
GlobalScope.launch {
|
||||
sessionScope.launch {
|
||||
val result = runCatching {
|
||||
activeSessionHolder.getActiveSession().fileService()
|
||||
.downloadFile(
|
||||
|
|
|
@ -60,6 +60,7 @@ class PinLocker @Inject constructor(
|
|||
return liveState
|
||||
}
|
||||
|
||||
@Suppress("EXPERIMENTAL_API_USAGE")
|
||||
private fun computeState() {
|
||||
GlobalScope.launch {
|
||||
val state = if (shouldBeLocked && pinCodeStore.hasEncodedPin()) {
|
||||
|
|
|
@ -88,6 +88,7 @@ class VectorFileLogger @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("EXPERIMENTAL_API_USAGE")
|
||||
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
|
||||
fileHandler ?: return
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
|
|
|
@ -19,6 +19,7 @@ import android.os.Bundle
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.databinding.EmojiChooserFragmentBinding
|
||||
|
@ -51,6 +52,8 @@ class EmojiChooserFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun getCoroutineScope() = lifecycleScope
|
||||
|
||||
override fun firstVisibleSectionChange(section: Int) {
|
||||
viewModel.setCurrentSection(section)
|
||||
}
|
||||
|
|
|
@ -31,8 +31,8 @@ import androidx.transition.AutoTransition
|
|||
import androidx.transition.TransitionManager
|
||||
import im.vector.app.R
|
||||
import im.vector.app.features.reactions.data.EmojiDataSource
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.abs
|
||||
|
@ -221,7 +221,7 @@ class EmojiRecyclerAdapter @Inject constructor(
|
|||
}
|
||||
|
||||
override fun getItemCount() = dataSource.rawData.categories
|
||||
.sumBy { emojiCategory -> 1 /* Section */ + emojiCategory.emojis.size }
|
||||
.sumOf { emojiCategory -> 1 /* Section */ + emojiCategory.emojis.size }
|
||||
|
||||
abstract class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
abstract fun bind(s: String?)
|
||||
|
@ -278,6 +278,7 @@ class EmojiRecyclerAdapter @Inject constructor(
|
|||
}
|
||||
|
||||
interface InteractionListener {
|
||||
fun getCoroutineScope(): CoroutineScope
|
||||
fun firstVisibleSectionChange(section: Int)
|
||||
}
|
||||
|
||||
|
@ -323,11 +324,11 @@ class EmojiRecyclerAdapter @Inject constructor(
|
|||
// Log.i("SCROLL SPEED","scroll speed $dy")
|
||||
isFastScroll = abs(dy) > 50
|
||||
val visible = (recyclerView.layoutManager as GridLayoutManager).findFirstCompletelyVisibleItemPosition()
|
||||
GlobalScope.launch {
|
||||
interactionListener?.getCoroutineScope()?.launch {
|
||||
val section = getSectionForAbsoluteIndex(visible)
|
||||
if (section != currentFirstVisibleSection) {
|
||||
currentFirstVisibleSection = section
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
interactionListener?.getCoroutineScope()?.launch(Dispatchers.Main) {
|
||||
interactionListener?.firstVisibleSectionChange(currentFirstVisibleSection)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.net.toUri
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.airbnb.mvrx.args
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
|
@ -36,6 +37,7 @@ import im.vector.app.databinding.FragmentRoomUploadsBinding
|
|||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.notifications.NotificationUtils
|
||||
import im.vector.app.features.roomprofile.RoomProfileArgs
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
import javax.inject.Inject
|
||||
|
@ -76,13 +78,21 @@ class RoomUploadsFragment @Inject constructor(
|
|||
shareMedia(requireContext(), it.file, getMimeTypeFromUri(requireContext(), it.file.toUri()))
|
||||
}
|
||||
is RoomUploadsViewEvents.FileReadyForSaving -> {
|
||||
saveMedia(
|
||||
context = requireContext(),
|
||||
file = it.file,
|
||||
title = it.title,
|
||||
mediaMimeType = getMimeTypeFromUri(requireContext(), it.file.toUri()),
|
||||
notificationUtils = notificationUtils
|
||||
)
|
||||
lifecycleScope.launch {
|
||||
runCatching {
|
||||
saveMedia(
|
||||
context = requireContext(),
|
||||
file = it.file,
|
||||
title = it.title,
|
||||
mediaMimeType = getMimeTypeFromUri(requireContext(), it.file.toUri()),
|
||||
notificationUtils = notificationUtils
|
||||
)
|
||||
}.onFailure { failure ->
|
||||
if (!isAdded) return@onFailure
|
||||
showErrorInSnackbar(failure)
|
||||
}
|
||||
}
|
||||
Unit
|
||||
}
|
||||
is RoomUploadsViewEvents.Failure -> showFailure(it.throwable)
|
||||
}.exhaustive
|
||||
|
|
|
@ -181,7 +181,7 @@ object VectorLocale {
|
|||
}
|
||||
}
|
||||
// sort by human display names
|
||||
.sortedBy { localeToLocalisedString(it).toLowerCase(it) }
|
||||
.sortedBy { localeToLocalisedString(it).lowercase(it) }
|
||||
|
||||
supportedLocales.clear()
|
||||
supportedLocales.addAll(list)
|
||||
|
|
|
@ -52,7 +52,6 @@ import im.vector.app.features.MainActivityArgs
|
|||
import im.vector.app.features.workers.signout.SignOutUiWorker
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.matrix.android.sdk.api.failure.isInvalidPassword
|
||||
|
@ -224,7 +223,7 @@ class VectorSettingsGeneralFragment @Inject constructor(
|
|||
it.summary = TextUtils.formatFileSize(requireContext(), size.toLong())
|
||||
|
||||
it.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
lifecycleScope.launch(Dispatchers.Main) {
|
||||
// On UI Thread
|
||||
displayLoadingView()
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import im.vector.app.core.epoxy.loadingItem
|
|||
import im.vector.app.core.epoxy.noResultItem
|
||||
import im.vector.app.core.epoxy.profiles.profileSectionItem
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.core.utils.safeCapitalize
|
||||
import im.vector.app.features.settings.VectorLocale
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import java.util.Locale
|
||||
|
@ -46,7 +47,7 @@ class LocalePickerController @Inject constructor(
|
|||
}
|
||||
localeItem {
|
||||
id(data.currentLocale.toString())
|
||||
title(VectorLocale.localeToLocalisedString(data.currentLocale).capitalize(data.currentLocale))
|
||||
title(VectorLocale.localeToLocalisedString(data.currentLocale).safeCapitalize(data.currentLocale))
|
||||
if (vectorPreferences.developerMode()) {
|
||||
subtitle(VectorLocale.localeToLocalisedStringInfo(data.currentLocale))
|
||||
}
|
||||
|
@ -75,7 +76,7 @@ class LocalePickerController @Inject constructor(
|
|||
.forEach {
|
||||
localeItem {
|
||||
id(it.toString())
|
||||
title(VectorLocale.localeToLocalisedString(it).capitalize(it))
|
||||
title(VectorLocale.localeToLocalisedString(it).safeCapitalize(it))
|
||||
if (vectorPreferences.developerMode()) {
|
||||
subtitle(VectorLocale.localeToLocalisedStringInfo(it))
|
||||
}
|
||||
|
|
|
@ -36,11 +36,11 @@ import im.vector.app.features.powerlevel.PowerLevelsObservableFactory
|
|||
import im.vector.app.features.rageshake.BugReporter
|
||||
import im.vector.app.features.rageshake.ReportType
|
||||
import im.vector.app.features.roomprofile.RoomProfileActivity
|
||||
import im.vector.app.features.session.coroutineScope
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import im.vector.app.features.spaces.manage.ManageType
|
||||
import im.vector.app.features.spaces.manage.SpaceManageActivity
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
|
@ -140,7 +140,7 @@ class SpaceSettingsMenuBottomSheet : VectorBaseBottomSheetDialogFragment<BottomS
|
|||
AlertDialog.Builder(requireContext())
|
||||
.setMessage(getString(R.string.space_leave_prompt_msg))
|
||||
.setPositiveButton(R.string.leave) { _, _ ->
|
||||
GlobalScope.launch {
|
||||
session.coroutineScope.launch {
|
||||
try {
|
||||
session.getRoom(spaceArgs.spaceId)?.leave(null)
|
||||
} catch (failure: Throwable) {
|
||||
|
|
|
@ -22,7 +22,7 @@ import dagger.assisted.AssistedInject
|
|||
import dagger.assisted.AssistedFactory
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import im.vector.app.features.session.coroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||
|
@ -465,7 +465,8 @@ class WidgetPostAPIHandler @AssistedInject constructor(@Assisted private val roo
|
|||
}
|
||||
|
||||
private fun launchWidgetAPIAction(widgetPostAPIMediator: WidgetPostAPIMediator, eventData: JsonDict, block: suspend () -> Unit): Job {
|
||||
return GlobalScope.launch {
|
||||
// We should probably use a scope tight to the lifecycle here...
|
||||
return session.coroutineScope.launch {
|
||||
kotlin.runCatching {
|
||||
block()
|
||||
}.fold(
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<array name="com_google_android_gms_fonts_certs">
|
||||
<item>@array/com_google_android_gms_fonts_certs_dev</item>
|
||||
<item>@array/com_google_android_gms_fonts_certs_prod</item>
|
||||
</array>
|
||||
<string-array name="com_google_android_gms_fonts_certs_dev">
|
||||
<item>
|
||||
<item tools:ignore="Typos">
|
||||
MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs=
|
||||
</item>
|
||||
</string-array>
|
||||
<string-array name="com_google_android_gms_fonts_certs_prod">
|
||||
<item>
|
||||
<item tools:ignore="Typos">
|
||||
MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK
|
||||
</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue