mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-23 09:56:00 +03:00
Merge pull request #2217 from vector-im/feature/bma/kotlin_version
Some upgrade
This commit is contained in:
commit
1fd24e746c
183 changed files with 1437 additions and 1420 deletions
|
@ -30,6 +30,10 @@ SDK API changes ⚠️:
|
|||
Build 🧱:
|
||||
- Use Update Gradle Wrapper Action
|
||||
- Updates Gradle Wrapper from 5.6.4 to 6.6.1. (#2193)
|
||||
- Upgrade kotlin version from `1.3.72` to `1.4.10` and kotlin coroutines version from `1.3.8` to `1.3.9`
|
||||
- Upgrade build tools from `3.5.3` to `4.0.1`
|
||||
- Upgrade com.google.gms:google-services from `4.3.2` to `4.3.4`
|
||||
- Upgrade Moshi to `1.11.0`, Dagger to `2.29.1`, Epoxy to `4.1.0`
|
||||
|
||||
Other changes:
|
||||
- Added registration/verification automated UI tests
|
||||
|
|
|
@ -58,21 +58,16 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.github.chrisbanes:PhotoView:2.0.0'
|
||||
implementation 'com.github.chrisbanes:PhotoView:2.1.4'
|
||||
|
||||
implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0'
|
||||
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
|
||||
|
||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
implementation 'androidx.core:core-ktx:1.3.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'com.google.android.material:material:1.1.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
implementation 'androidx.navigation:navigation-fragment-ktx:2.1.0'
|
||||
implementation 'androidx.navigation:navigation-ui-ktx:2.1.0'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
implementation 'androidx.core:core-ktx:1.3.2'
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation "androidx.fragment:fragment:1.3.0-beta01"
|
||||
implementation "androidx.recyclerview:recyclerview:1.1.0"
|
||||
|
||||
implementation 'com.google.android.material:material:1.2.1'
|
||||
}
|
13
build.gradle
13
build.gradle
|
@ -1,7 +1,9 @@
|
|||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.72'
|
||||
// Ref: https://kotlinlang.org/releases.html
|
||||
ext.kotlin_version = '1.4.10'
|
||||
ext.kotlin_coroutines_version = "1.3.9"
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
|
@ -10,10 +12,8 @@ buildscript {
|
|||
}
|
||||
}
|
||||
dependencies {
|
||||
// Warning: 3.6.3 leads to infinite gradle builds. Stick to 3.5.3 for the moment
|
||||
classpath 'com.android.tools.build:gradle:3.5.3'
|
||||
classpath 'com.google.gms:google-services:4.3.2'
|
||||
classpath "com.airbnb.okreplay:gradle-plugin:1.5.0"
|
||||
classpath 'com.android.tools.build:gradle:4.0.1'
|
||||
classpath 'com.google.gms:google-services:4.3.4'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.7.1'
|
||||
classpath 'com.google.android.gms:oss-licenses-plugin:0.10.2'
|
||||
|
@ -64,7 +64,8 @@ allprojects {
|
|||
|
||||
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
|
||||
// Warnings are potential errors, so stop ignoring them
|
||||
kotlinOptions.allWarningsAsErrors = true
|
||||
// You can override by passing `-PallWarningsAsErrors=false` in the command line
|
||||
kotlinOptions.allWarningsAsErrors = project.properties['allWarningsAsErrors']?.toBoolean() ?: true
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,7 +35,8 @@ android {
|
|||
|
||||
dependencies {
|
||||
implementation project(":matrix-sdk-android")
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation "androidx.fragment:fragment:1.3.0-beta01"
|
||||
implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0'
|
||||
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
|
||||
// Paging
|
||||
|
@ -43,8 +44,4 @@ dependencies {
|
|||
|
||||
// Logging
|
||||
implementation 'com.jakewharton.timber:timber:4.7.1'
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test:runner:1.2.0'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ apply plugin: 'kotlin-android'
|
|||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'realm-android'
|
||||
apply plugin: 'okreplay'
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
|
@ -109,21 +108,21 @@ static def gitRevisionDate() {
|
|||
dependencies {
|
||||
|
||||
def arrow_version = "0.8.2"
|
||||
def moshi_version = '1.8.0'
|
||||
def moshi_version = '1.11.0'
|
||||
def lifecycle_version = '2.2.0'
|
||||
def arch_version = '2.1.0'
|
||||
def coroutines_version = "1.3.8"
|
||||
def markwon_version = '3.1.0'
|
||||
def daggerVersion = '2.25.4'
|
||||
def daggerVersion = '2.29.1'
|
||||
def work_version = '2.4.0'
|
||||
def retrofit_version = '2.6.2'
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
|
||||
|
||||
implementation "androidx.appcompat:appcompat:1.2.0"
|
||||
implementation "androidx.core:core-ktx:1.3.1"
|
||||
implementation "androidx.fragment:fragment:1.3.0-beta01"
|
||||
implementation "androidx.core:core-ktx:1.3.2"
|
||||
|
||||
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
|
||||
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
|
||||
|
@ -143,7 +142,7 @@ dependencies {
|
|||
implementation "ru.noties.markwon:core:$markwon_version"
|
||||
|
||||
// Image
|
||||
implementation 'androidx.exifinterface:exifinterface:1.3.0-alpha01'
|
||||
implementation 'androidx.exifinterface:exifinterface:1.3.0'
|
||||
|
||||
// Database
|
||||
implementation 'com.github.Zhuinden:realm-monarchy:0.5.1'
|
||||
|
@ -181,33 +180,29 @@ dependencies {
|
|||
// Use the same WebRTC library than the one used by Jitsi library
|
||||
implementation('com.facebook.react:react-native-webrtc:1.84.0-jitsi-5112273@aar')
|
||||
|
||||
debugImplementation 'com.airbnb.okreplay:okreplay:1.5.0'
|
||||
releaseImplementation 'com.airbnb.okreplay:noop:1.5.0'
|
||||
androidTestImplementation 'com.airbnb.okreplay:espresso:1.5.0'
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
testImplementation 'junit:junit:4.13'
|
||||
testImplementation 'org.robolectric:robolectric:4.3'
|
||||
//testImplementation 'org.robolectric:shadows-support-v4:3.0'
|
||||
// Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281
|
||||
testImplementation 'io.mockk:mockk:1.9.2.kotlin12'
|
||||
testImplementation 'org.amshove.kluent:kluent-android:1.44'
|
||||
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
|
||||
testImplementation 'org.amshove.kluent:kluent-android:1.61'
|
||||
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
|
||||
// Plant Timber tree for test
|
||||
testImplementation 'net.lachlanmckee:timber-junit-rule:1.0.1'
|
||||
|
||||
kaptAndroidTest "com.google.dagger:dagger-compiler:$daggerVersion"
|
||||
androidTestImplementation 'androidx.test:core:1.2.0'
|
||||
androidTestImplementation 'androidx.test:runner:1.2.0'
|
||||
androidTestImplementation 'androidx.test:rules:1.2.0'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
androidTestImplementation 'org.amshove.kluent:kluent-android:1.44'
|
||||
androidTestImplementation 'androidx.test:core:1.3.0'
|
||||
androidTestImplementation 'androidx.test:runner:1.3.0'
|
||||
androidTestImplementation 'androidx.test:rules:1.3.0'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
||||
androidTestImplementation 'org.amshove.kluent:kluent-android:1.61'
|
||||
// Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281
|
||||
androidTestImplementation 'io.mockk:mockk-android:1.9.2.kotlin12'
|
||||
androidTestImplementation "androidx.arch.core:core-testing:$arch_version"
|
||||
androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
|
||||
androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
|
||||
// Plant Timber tree for test
|
||||
androidTestImplementation 'net.lachlanmckee:timber-junit-rule:1.0.1'
|
||||
|
||||
androidTestUtil 'androidx.test:orchestrator:1.2.0'
|
||||
androidTestUtil 'androidx.test:orchestrator:1.3.0'
|
||||
}
|
||||
|
|
|
@ -20,9 +20,11 @@ package org.matrix.android.sdk.api.session.content
|
|||
import android.net.Uri
|
||||
import android.os.Parcelable
|
||||
import androidx.exifinterface.media.ExifInterface
|
||||
import com.squareup.moshi.JsonClass
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
|
||||
@Parcelize
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class ContentAttachmentData(
|
||||
val size: Long = 0,
|
||||
val duration: Long? = 0,
|
||||
|
@ -32,10 +34,11 @@ data class ContentAttachmentData(
|
|||
val exifOrientation: Int = ExifInterface.ORIENTATION_UNDEFINED,
|
||||
val name: String? = null,
|
||||
val queryUri: Uri,
|
||||
private val mimeType: String?,
|
||||
val mimeType: String?,
|
||||
val type: Type
|
||||
) : Parcelable {
|
||||
|
||||
@JsonClass(generateAdapter = false)
|
||||
enum class Type {
|
||||
FILE,
|
||||
IMAGE,
|
||||
|
|
|
@ -18,7 +18,9 @@
|
|||
package org.matrix.android.sdk.api.session.room.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class Signed(
|
||||
@Json(name = "token") val token: String,
|
||||
@Json(name = "signatures") val signatures: Any,
|
||||
|
|
|
@ -105,6 +105,6 @@ private fun Versions.doesServerSeparatesAddAndBind(): Boolean {
|
|||
private fun Versions.getMaxVersion(): HomeServerVersion {
|
||||
return supportedVersions
|
||||
?.mapNotNull { HomeServerVersion.parse(it) }
|
||||
?.max()
|
||||
?.maxOrNull()
|
||||
?: HomeServerVersion.r0_0_0
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
package org.matrix.android.sdk.internal.crypto
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.auth.data.Credentials
|
||||
import org.matrix.android.sdk.api.crypto.MXCryptoConfig
|
||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME
|
||||
|
@ -36,8 +38,6 @@ import org.matrix.android.sdk.internal.di.SessionId
|
|||
import org.matrix.android.sdk.internal.session.SessionScope
|
||||
import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
|
||||
import org.matrix.android.sdk.internal.worker.WorkerParamsFactory
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -327,7 +327,9 @@ internal class IncomingGossipingRequestManager @Inject constructor(
|
|||
val params = SendGossipWorker.Params(
|
||||
sessionId = sessionId,
|
||||
secretValue = secretValue,
|
||||
request = request
|
||||
requestUserId = request.userId,
|
||||
requestDeviceId = request.deviceId,
|
||||
requestId = request.requestId
|
||||
)
|
||||
|
||||
cryptoStore.updateGossipingRequestState(request, GossipingRequestState.ACCEPTING)
|
||||
|
@ -351,7 +353,9 @@ internal class IncomingGossipingRequestManager @Inject constructor(
|
|||
val params = SendGossipWorker.Params(
|
||||
sessionId = userId,
|
||||
secretValue = secretValue,
|
||||
request = request
|
||||
requestUserId = request.userId,
|
||||
requestDeviceId = request.deviceId,
|
||||
requestId = request.requestId
|
||||
)
|
||||
|
||||
cryptoStore.updateGossipingRequestState(request, GossipingRequestState.ACCEPTING)
|
||||
|
|
|
@ -22,7 +22,7 @@ import org.matrix.android.sdk.api.session.events.model.toModel
|
|||
import org.matrix.android.sdk.internal.crypto.model.rest.SecretShareRequest
|
||||
|
||||
/**
|
||||
* IncomingRoomKeyRequest class defines the incoming room keys request.
|
||||
* IncomingSecretShareRequest class defines the incoming secret keys request.
|
||||
*/
|
||||
data class IncomingSecretShareRequest(
|
||||
/**
|
||||
|
|
|
@ -47,7 +47,9 @@ internal class SendGossipWorker(context: Context,
|
|||
internal data class Params(
|
||||
override val sessionId: String,
|
||||
val secretValue: String,
|
||||
val request: IncomingSecretShareRequest,
|
||||
val requestUserId: String?,
|
||||
val requestDeviceId: String?,
|
||||
val requestId: String?,
|
||||
override val lastFailureMessage: String? = null
|
||||
) : SessionWorkerParams
|
||||
|
||||
|
@ -67,16 +69,21 @@ internal class SendGossipWorker(context: Context,
|
|||
val eventType: String = EventType.SEND_SECRET
|
||||
|
||||
val toDeviceContent = SecretSendEventContent(
|
||||
requestId = params.request.requestId ?: "",
|
||||
requestId = params.requestId ?: "",
|
||||
secretValue = params.secretValue
|
||||
)
|
||||
|
||||
val requestingUserId = params.request.userId ?: ""
|
||||
val requestingDeviceId = params.request.deviceId ?: ""
|
||||
val requestingUserId = params.requestUserId ?: ""
|
||||
val requestingDeviceId = params.requestDeviceId ?: ""
|
||||
val deviceInfo = cryptoStore.getUserDevice(requestingUserId, requestingDeviceId)
|
||||
?: return buildErrorResult(params, "Unknown deviceInfo, cannot send message").also {
|
||||
cryptoStore.updateGossipingRequestState(params.request, GossipingRequestState.FAILED_TO_ACCEPTED)
|
||||
Timber.e("Unknown deviceInfo, cannot send message, sessionId: ${params.request.deviceId}")
|
||||
cryptoStore.updateGossipingRequestState(
|
||||
requestUserId = params.requestUserId,
|
||||
requestDeviceId = params.requestDeviceId,
|
||||
requestId = params.requestId,
|
||||
state = GossipingRequestState.FAILED_TO_ACCEPTED
|
||||
)
|
||||
Timber.e("Unknown deviceInfo, cannot send message, sessionId: ${params.requestDeviceId}")
|
||||
}
|
||||
|
||||
val sendToDeviceMap = MXUsersDevicesMap<Any>()
|
||||
|
@ -88,7 +95,12 @@ internal class SendGossipWorker(context: Context,
|
|||
// no session with this device, probably because there
|
||||
// were no one-time keys.
|
||||
return buildErrorResult(params, "no session with this device").also {
|
||||
cryptoStore.updateGossipingRequestState(params.request, GossipingRequestState.FAILED_TO_ACCEPTED)
|
||||
cryptoStore.updateGossipingRequestState(
|
||||
requestUserId = params.requestUserId,
|
||||
requestDeviceId = params.requestDeviceId,
|
||||
requestId = params.requestId,
|
||||
state = GossipingRequestState.FAILED_TO_ACCEPTED
|
||||
)
|
||||
Timber.e("no session with this device, probably because there were no one-time keys.")
|
||||
}
|
||||
}
|
||||
|
@ -121,13 +133,23 @@ internal class SendGossipWorker(context: Context,
|
|||
transactionId = localId
|
||||
)
|
||||
)
|
||||
cryptoStore.updateGossipingRequestState(params.request, GossipingRequestState.ACCEPTED)
|
||||
cryptoStore.updateGossipingRequestState(
|
||||
requestUserId = params.requestUserId,
|
||||
requestDeviceId = params.requestDeviceId,
|
||||
requestId = params.requestId,
|
||||
state = GossipingRequestState.ACCEPTED
|
||||
)
|
||||
return Result.success()
|
||||
} catch (throwable: Throwable) {
|
||||
return if (throwable.shouldBeRetried()) {
|
||||
Result.retry()
|
||||
} else {
|
||||
cryptoStore.updateGossipingRequestState(params.request, GossipingRequestState.FAILED_TO_ACCEPTED)
|
||||
cryptoStore.updateGossipingRequestState(
|
||||
requestUserId = params.requestUserId,
|
||||
requestDeviceId = params.requestDeviceId,
|
||||
requestId = params.requestId,
|
||||
state = GossipingRequestState.FAILED_TO_ACCEPTED
|
||||
)
|
||||
buildErrorResult(params, throwable.localizedMessage ?: "error")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,12 @@
|
|||
|
||||
package org.matrix.android.sdk.internal.crypto.keysbackup.model.rest
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class KeysVersion(
|
||||
// the keys backup version
|
||||
var version: String? = null
|
||||
@Json(name = "version")
|
||||
val version: String? = null
|
||||
)
|
||||
|
|
|
@ -371,7 +371,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
|
|||
callback.onFailure(SharedSecretStorageError.BadKeyFormat)
|
||||
}
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.main) {
|
||||
kotlin.runCatching {
|
||||
runCatching {
|
||||
// decrypt from recovery key
|
||||
withOlmDecryption { olmPkDecryption ->
|
||||
olmPkDecryption.setPrivateKey(keySpec.privateKey)
|
||||
|
@ -390,7 +390,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
|
|||
callback.onFailure(SharedSecretStorageError.BadKeyFormat)
|
||||
}
|
||||
cryptoCoroutineScope.launch(coroutineDispatchers.main) {
|
||||
kotlin.runCatching {
|
||||
runCatching {
|
||||
decryptAesHmacSha2(keySpec, name, secretContent)
|
||||
}.foldToCallback(callback)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
/*
|
||||
* Copyright 2016 OpenMarket Ltd
|
||||
* Copyright 2018 New Vector Ltd
|
||||
|
@ -215,11 +214,12 @@ internal interface IMXCryptoStore {
|
|||
// TODO temp
|
||||
fun getLiveDeviceList(): LiveData<List<CryptoDeviceInfo>>
|
||||
|
||||
fun getMyDevicesInfo() : List<DeviceInfo>
|
||||
fun getMyDevicesInfo(): List<DeviceInfo>
|
||||
|
||||
fun getLiveMyDevicesInfo() : LiveData<List<DeviceInfo>>
|
||||
fun getLiveMyDevicesInfo(): LiveData<List<DeviceInfo>>
|
||||
|
||||
fun saveMyDevicesInfo(info: List<DeviceInfo>)
|
||||
|
||||
/**
|
||||
* Store the crypto algorithm for a room.
|
||||
*
|
||||
|
@ -367,7 +367,19 @@ internal interface IMXCryptoStore {
|
|||
|
||||
fun saveGossipingEvent(event: Event)
|
||||
|
||||
fun updateGossipingRequestState(request: IncomingShareRequestCommon, state: GossipingRequestState)
|
||||
fun updateGossipingRequestState(request: IncomingShareRequestCommon, state: GossipingRequestState) {
|
||||
updateGossipingRequestState(
|
||||
requestUserId = request.userId,
|
||||
requestDeviceId = request.deviceId,
|
||||
requestId = request.requestId,
|
||||
state = state
|
||||
)
|
||||
}
|
||||
|
||||
fun updateGossipingRequestState(requestUserId: String?,
|
||||
requestDeviceId: String?,
|
||||
requestId: String?,
|
||||
state: GossipingRequestState)
|
||||
|
||||
/**
|
||||
* Search an IncomingRoomKeyRequest
|
||||
|
@ -411,7 +423,7 @@ internal interface IMXCryptoStore {
|
|||
fun getLiveCrossSigningPrivateKeys(): LiveData<Optional<PrivateKeysInfo>>
|
||||
|
||||
fun saveBackupRecoveryKey(recoveryKey: String?, version: String?)
|
||||
fun getKeyBackupRecoveryKeyInfo() : SavedKeyBackupKeyInfo?
|
||||
fun getKeyBackupRecoveryKeyInfo(): SavedKeyBackupKeyInfo?
|
||||
|
||||
fun setUserKeysAsTrusted(userId: String, trusted: Boolean = true)
|
||||
fun setDeviceTrust(userId: String, deviceId: String, crossSignedVerified: Boolean, locallyVerified: Boolean?)
|
||||
|
@ -421,12 +433,13 @@ internal interface IMXCryptoStore {
|
|||
fun updateUsersTrust(check: (String) -> Boolean)
|
||||
|
||||
fun addWithHeldMegolmSession(withHeldContent: RoomKeyWithHeldContent)
|
||||
fun getWithHeldMegolmSession(roomId: String, sessionId: String) : RoomKeyWithHeldContent?
|
||||
fun getWithHeldMegolmSession(roomId: String, sessionId: String): RoomKeyWithHeldContent?
|
||||
|
||||
fun markedSessionAsShared(roomId: String?, sessionId: String, userId: String, deviceId: String, chainIndex: Int)
|
||||
fun wasSessionSharedWithUser(roomId: String?, sessionId: String, userId: String, deviceId: String) : SharedSessionResult
|
||||
fun wasSessionSharedWithUser(roomId: String?, sessionId: String, userId: String, deviceId: String): SharedSessionResult
|
||||
data class SharedSessionResult(val found: Boolean, val chainIndex: Int?)
|
||||
fun getSharedWithInfo(roomId: String?, sessionId: String) : MXUsersDevicesMap<Int>
|
||||
|
||||
fun getSharedWithInfo(roomId: String?, sessionId: String): MXUsersDevicesMap<Int>
|
||||
// Dev tools
|
||||
|
||||
fun getOutgoingRoomKeyRequests(): List<OutgoingRoomKeyRequest>
|
||||
|
|
|
@ -1134,12 +1134,15 @@ internal class RealmCryptoStore @Inject constructor(
|
|||
// }
|
||||
// }
|
||||
|
||||
override fun updateGossipingRequestState(request: IncomingShareRequestCommon, state: GossipingRequestState) {
|
||||
override fun updateGossipingRequestState(requestUserId: String?,
|
||||
requestDeviceId: String?,
|
||||
requestId: String?,
|
||||
state: GossipingRequestState) {
|
||||
doRealmTransaction(realmConfiguration) { realm ->
|
||||
realm.where<IncomingGossipingRequestEntity>()
|
||||
.equalTo(IncomingGossipingRequestEntityFields.OTHER_USER_ID, request.userId)
|
||||
.equalTo(IncomingGossipingRequestEntityFields.OTHER_DEVICE_ID, request.deviceId)
|
||||
.equalTo(IncomingGossipingRequestEntityFields.REQUEST_ID, request.requestId)
|
||||
.equalTo(IncomingGossipingRequestEntityFields.OTHER_USER_ID, requestUserId)
|
||||
.equalTo(IncomingGossipingRequestEntityFields.OTHER_DEVICE_ID, requestDeviceId)
|
||||
.equalTo(IncomingGossipingRequestEntityFields.REQUEST_ID, requestId)
|
||||
.findAll().forEach {
|
||||
it.requestState = state
|
||||
}
|
||||
|
|
|
@ -32,8 +32,10 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent
|
|||
import org.matrix.android.sdk.api.session.room.model.message.MessageType
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationRequestContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent
|
||||
import org.matrix.android.sdk.internal.network.parsing.CipherSuiteMoshiAdapter
|
||||
import org.matrix.android.sdk.internal.network.parsing.ForceToBooleanJsonAdapter
|
||||
import org.matrix.android.sdk.internal.network.parsing.RuntimeJsonAdapterFactory
|
||||
import org.matrix.android.sdk.internal.network.parsing.TlsVersionMoshiAdapter
|
||||
import org.matrix.android.sdk.internal.network.parsing.UriMoshiAdapter
|
||||
|
||||
object MoshiProvider {
|
||||
|
@ -41,6 +43,8 @@ object MoshiProvider {
|
|||
private val moshi: Moshi = Moshi.Builder()
|
||||
.add(UriMoshiAdapter())
|
||||
.add(ForceToBooleanJsonAdapter())
|
||||
.add(CipherSuiteMoshiAdapter())
|
||||
.add(TlsVersionMoshiAdapter())
|
||||
.add(RuntimeJsonAdapterFactory.of(MessageContent::class.java, "msgtype", MessageDefaultContent::class.java)
|
||||
.registerSubtype(MessageTextContent::class.java, MessageType.MSGTYPE_TEXT)
|
||||
.registerSubtype(MessageNoticeContent::class.java, MessageType.MSGTYPE_NOTICE)
|
||||
|
|
|
@ -29,7 +29,6 @@ import org.matrix.android.sdk.internal.network.interceptors.CurlLoggingIntercept
|
|||
import org.matrix.android.sdk.internal.network.interceptors.FormattedJsonHttpLogger
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import okreplay.OkReplayInterceptor
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@Module
|
||||
|
@ -44,12 +43,6 @@ internal object NetworkModule {
|
|||
return interceptor
|
||||
}
|
||||
|
||||
@Provides
|
||||
@JvmStatic
|
||||
fun providesOkReplayInterceptor(): OkReplayInterceptor {
|
||||
return OkReplayInterceptor()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@JvmStatic
|
||||
fun providesStethoInterceptor(): StethoInterceptor {
|
||||
|
@ -71,8 +64,7 @@ internal object NetworkModule {
|
|||
timeoutInterceptor: TimeOutInterceptor,
|
||||
userAgentInterceptor: UserAgentInterceptor,
|
||||
httpLoggingInterceptor: HttpLoggingInterceptor,
|
||||
curlLoggingInterceptor: CurlLoggingInterceptor,
|
||||
okReplayInterceptor: OkReplayInterceptor): OkHttpClient {
|
||||
curlLoggingInterceptor: CurlLoggingInterceptor): OkHttpClient {
|
||||
return OkHttpClient.Builder()
|
||||
.connectTimeout(30, TimeUnit.SECONDS)
|
||||
.readTimeout(60, TimeUnit.SECONDS)
|
||||
|
@ -93,7 +85,6 @@ internal object NetworkModule {
|
|||
proxy(it)
|
||||
}
|
||||
}
|
||||
.addInterceptor(okReplayInterceptor)
|
||||
.build()
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* 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 org.matrix.android.sdk.internal.network.parsing
|
||||
|
||||
import com.squareup.moshi.FromJson
|
||||
import com.squareup.moshi.ToJson
|
||||
import okhttp3.CipherSuite
|
||||
|
||||
internal class CipherSuiteMoshiAdapter {
|
||||
|
||||
@ToJson
|
||||
fun toJson(cipherSuite: CipherSuite): String {
|
||||
return cipherSuite.javaName
|
||||
}
|
||||
|
||||
@FromJson
|
||||
fun fromJson(cipherSuiteString: String): CipherSuite {
|
||||
return CipherSuite.forJavaName(cipherSuiteString)
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -14,19 +15,21 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk
|
||||
package org.matrix.android.sdk.internal.network.parsing
|
||||
|
||||
import okreplay.OkReplayConfig
|
||||
import okreplay.PermissionRule
|
||||
import okreplay.RecorderRule
|
||||
import org.junit.rules.RuleChain
|
||||
import org.junit.rules.TestRule
|
||||
import com.squareup.moshi.FromJson
|
||||
import com.squareup.moshi.ToJson
|
||||
import okhttp3.TlsVersion
|
||||
|
||||
class OkReplayRuleChainNoActivity(
|
||||
private val configuration: OkReplayConfig) {
|
||||
internal class TlsVersionMoshiAdapter {
|
||||
|
||||
fun get(): TestRule {
|
||||
return RuleChain.outerRule(PermissionRule(configuration))
|
||||
.around(RecorderRule(configuration))
|
||||
@ToJson
|
||||
fun toJson(tlsVersion: TlsVersion): String {
|
||||
return tlsVersion.javaName
|
||||
}
|
||||
|
||||
@FromJson
|
||||
fun fromJson(tlsVersionString: String): TlsVersion {
|
||||
return TlsVersion.forJavaName(tlsVersionString)
|
||||
}
|
||||
}
|
|
@ -41,15 +41,10 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'androidx.core:core-ktx:1.3.0'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
|
||||
implementation 'androidx.exifinterface:exifinterface:1.3.0-alpha01'
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation "androidx.fragment:fragment:1.3.0-beta01"
|
||||
implementation 'androidx.exifinterface:exifinterface:1.3.0'
|
||||
|
||||
// Log
|
||||
implementation 'com.jakewharton.timber:timber:4.7.1'
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package im.vector.lib.multipicker
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.media.MediaMetadataRetriever
|
||||
|
@ -26,19 +25,13 @@ import im.vector.lib.multipicker.entity.MultiPickerAudioType
|
|||
/**
|
||||
* Audio file picker implementation
|
||||
*/
|
||||
class AudioPicker(override val requestCode: Int) : Picker<MultiPickerAudioType>(requestCode) {
|
||||
class AudioPicker : Picker<MultiPickerAudioType>() {
|
||||
|
||||
/**
|
||||
* Call this function from onActivityResult(int, int, Intent).
|
||||
* Returns selected audio files or empty list if request code is wrong
|
||||
* or result code is not Activity.RESULT_OK
|
||||
* or user did not select any files.
|
||||
* Returns selected audio files or empty list if user did not select any files.
|
||||
*/
|
||||
override fun getSelectedFiles(context: Context, requestCode: Int, resultCode: Int, data: Intent?): List<MultiPickerAudioType> {
|
||||
if (requestCode != this.requestCode && resultCode != Activity.RESULT_OK) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override fun getSelectedFiles(context: Context, data: Intent?): List<MultiPickerAudioType> {
|
||||
val audioList = mutableListOf<MultiPickerAudioType>()
|
||||
|
||||
getSelectedUriList(data).forEach { selectedUri ->
|
||||
|
|
|
@ -16,13 +16,12 @@
|
|||
|
||||
package im.vector.lib.multipicker
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.provider.MediaStore
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.fragment.app.Fragment
|
||||
import im.vector.lib.multipicker.entity.MultiPickerImageType
|
||||
import im.vector.lib.multipicker.utils.ImageUtils
|
||||
import java.io.File
|
||||
|
@ -33,33 +32,18 @@ import java.util.Locale
|
|||
/**
|
||||
* Implementation of taking a photo with Camera
|
||||
*/
|
||||
class CameraPicker(val requestCode: Int) {
|
||||
class CameraPicker {
|
||||
|
||||
/**
|
||||
* Start camera by using an Activity
|
||||
* @param activity Activity to handle onActivityResult().
|
||||
* Start camera by using a ActivityResultLauncher
|
||||
* @return Uri of taken photo or null if the operation is cancelled.
|
||||
*/
|
||||
fun startWithExpectingFile(activity: Activity): Uri? {
|
||||
val photoUri = createPhotoUri(activity)
|
||||
fun startWithExpectingFile(context: Context, activityResultLauncher: ActivityResultLauncher<Intent>): Uri? {
|
||||
val photoUri = createPhotoUri(context)
|
||||
val intent = createIntent().apply {
|
||||
putExtra(MediaStore.EXTRA_OUTPUT, photoUri)
|
||||
}
|
||||
activity.startActivityForResult(intent, requestCode)
|
||||
return photoUri
|
||||
}
|
||||
|
||||
/**
|
||||
* Start camera by using a Fragment
|
||||
* @param fragment Fragment to handle onActivityResult().
|
||||
* @return Uri of taken photo or null if the operation is cancelled.
|
||||
*/
|
||||
fun startWithExpectingFile(fragment: Fragment): Uri? {
|
||||
val photoUri = createPhotoUri(fragment.requireContext())
|
||||
val intent = createIntent().apply {
|
||||
putExtra(MediaStore.EXTRA_OUTPUT, photoUri)
|
||||
}
|
||||
fragment.startActivityForResult(intent, requestCode)
|
||||
activityResultLauncher.launch(intent)
|
||||
return photoUri
|
||||
}
|
||||
|
||||
|
@ -69,40 +53,38 @@ class CameraPicker(val requestCode: Int) {
|
|||
* or result code is not Activity.RESULT_OK
|
||||
* or user cancelled the operation.
|
||||
*/
|
||||
fun getTakenPhoto(context: Context, requestCode: Int, resultCode: Int, photoUri: Uri): MultiPickerImageType? {
|
||||
if (requestCode == this.requestCode && resultCode == Activity.RESULT_OK) {
|
||||
val projection = arrayOf(
|
||||
MediaStore.Images.Media.DISPLAY_NAME,
|
||||
MediaStore.Images.Media.SIZE
|
||||
)
|
||||
fun getTakenPhoto(context: Context, photoUri: Uri): MultiPickerImageType? {
|
||||
val projection = arrayOf(
|
||||
MediaStore.Images.Media.DISPLAY_NAME,
|
||||
MediaStore.Images.Media.SIZE
|
||||
)
|
||||
|
||||
context.contentResolver.query(
|
||||
photoUri,
|
||||
projection,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)?.use { cursor ->
|
||||
val nameColumn = cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME)
|
||||
val sizeColumn = cursor.getColumnIndex(MediaStore.Images.Media.SIZE)
|
||||
context.contentResolver.query(
|
||||
photoUri,
|
||||
projection,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)?.use { cursor ->
|
||||
val nameColumn = cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME)
|
||||
val sizeColumn = cursor.getColumnIndex(MediaStore.Images.Media.SIZE)
|
||||
|
||||
if (cursor.moveToNext()) {
|
||||
val name = cursor.getString(nameColumn)
|
||||
val size = cursor.getLong(sizeColumn)
|
||||
if (cursor.moveToNext()) {
|
||||
val name = cursor.getString(nameColumn)
|
||||
val size = cursor.getLong(sizeColumn)
|
||||
|
||||
val bitmap = ImageUtils.getBitmap(context, photoUri)
|
||||
val orientation = ImageUtils.getOrientation(context, photoUri)
|
||||
val bitmap = ImageUtils.getBitmap(context, photoUri)
|
||||
val orientation = ImageUtils.getOrientation(context, photoUri)
|
||||
|
||||
return MultiPickerImageType(
|
||||
name,
|
||||
size,
|
||||
context.contentResolver.getType(photoUri),
|
||||
photoUri,
|
||||
bitmap?.width ?: 0,
|
||||
bitmap?.height ?: 0,
|
||||
orientation
|
||||
)
|
||||
}
|
||||
return MultiPickerImageType(
|
||||
name,
|
||||
size,
|
||||
context.contentResolver.getType(photoUri),
|
||||
photoUri,
|
||||
bitmap?.width ?: 0,
|
||||
bitmap?.height ?: 0,
|
||||
orientation
|
||||
)
|
||||
}
|
||||
}
|
||||
return null
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package im.vector.lib.multipicker
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
|
@ -26,19 +25,13 @@ import im.vector.lib.multipicker.entity.MultiPickerContactType
|
|||
/**
|
||||
* Contact Picker implementation
|
||||
*/
|
||||
class ContactPicker(override val requestCode: Int) : Picker<MultiPickerContactType>(requestCode) {
|
||||
class ContactPicker : Picker<MultiPickerContactType>() {
|
||||
|
||||
/**
|
||||
* Call this function from onActivityResult(int, int, Intent).
|
||||
* Returns selected contact or empty list if request code is wrong
|
||||
* or result code is not Activity.RESULT_OK
|
||||
* or user did not select any files.
|
||||
* Returns selected contact or empty list if user did not select any contacts.
|
||||
*/
|
||||
override fun getSelectedFiles(context: Context, requestCode: Int, resultCode: Int, data: Intent?): List<MultiPickerContactType> {
|
||||
if (requestCode != this.requestCode && resultCode != Activity.RESULT_OK) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override fun getSelectedFiles(context: Context, data: Intent?): List<MultiPickerContactType> {
|
||||
val contactList = mutableListOf<MultiPickerContactType>()
|
||||
|
||||
data?.data?.let { selectedUri ->
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package im.vector.lib.multipicker
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.provider.OpenableColumns
|
||||
|
@ -25,19 +24,13 @@ import im.vector.lib.multipicker.entity.MultiPickerFileType
|
|||
/**
|
||||
* Implementation of selecting any type of files
|
||||
*/
|
||||
class FilePicker(override val requestCode: Int) : Picker<MultiPickerFileType>(requestCode) {
|
||||
class FilePicker : Picker<MultiPickerFileType>() {
|
||||
|
||||
/**
|
||||
* Call this function from onActivityResult(int, int, Intent).
|
||||
* Returns selected files or empty list if request code is wrong
|
||||
* or result code is not Activity.RESULT_OK
|
||||
* or user did not select any files.
|
||||
* Returns selected files or empty list if user did not select any files.
|
||||
*/
|
||||
override fun getSelectedFiles(context: Context, requestCode: Int, resultCode: Int, data: Intent?): List<MultiPickerFileType> {
|
||||
if (requestCode != this.requestCode && resultCode != Activity.RESULT_OK) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override fun getSelectedFiles(context: Context, data: Intent?): List<MultiPickerFileType> {
|
||||
val fileList = mutableListOf<MultiPickerFileType>()
|
||||
|
||||
getSelectedUriList(data).forEach { selectedUri ->
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package im.vector.lib.multipicker
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.provider.MediaStore
|
||||
|
@ -26,19 +25,13 @@ import im.vector.lib.multipicker.utils.ImageUtils
|
|||
/**
|
||||
* Image Picker implementation
|
||||
*/
|
||||
class ImagePicker(override val requestCode: Int) : Picker<MultiPickerImageType>(requestCode) {
|
||||
class ImagePicker : Picker<MultiPickerImageType>() {
|
||||
|
||||
/**
|
||||
* Call this function from onActivityResult(int, int, Intent).
|
||||
* Returns selected image files or empty list if request code is wrong
|
||||
* or result code is not Activity.RESULT_OK
|
||||
* or user did not select any files.
|
||||
* Returns selected image files or empty list if user did not select any files.
|
||||
*/
|
||||
override fun getSelectedFiles(context: Context, requestCode: Int, resultCode: Int, data: Intent?): List<MultiPickerImageType> {
|
||||
if (requestCode != this.requestCode && resultCode != Activity.RESULT_OK) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override fun getSelectedFiles(context: Context, data: Intent?): List<MultiPickerImageType> {
|
||||
val imageList = mutableListOf<MultiPickerImageType>()
|
||||
|
||||
getSelectedUriList(data).forEach { selectedUri ->
|
||||
|
|
|
@ -26,23 +26,16 @@ class MultiPicker<T> {
|
|||
val CONTACT by lazy { MultiPicker<ContactPicker>() }
|
||||
val CAMERA by lazy { MultiPicker<CameraPicker>() }
|
||||
|
||||
const val REQUEST_CODE_PICK_IMAGE = 5000
|
||||
const val REQUEST_CODE_PICK_VIDEO = 5001
|
||||
const val REQUEST_CODE_PICK_FILE = 5002
|
||||
const val REQUEST_CODE_PICK_AUDIO = 5003
|
||||
const val REQUEST_CODE_PICK_CONTACT = 5004
|
||||
const val REQUEST_CODE_TAKE_PHOTO = 5005
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T> get(type: MultiPicker<T>): T {
|
||||
return when (type) {
|
||||
IMAGE -> ImagePicker(REQUEST_CODE_PICK_IMAGE) as T
|
||||
VIDEO -> VideoPicker(REQUEST_CODE_PICK_VIDEO) as T
|
||||
FILE -> FilePicker(REQUEST_CODE_PICK_FILE) as T
|
||||
AUDIO -> AudioPicker(REQUEST_CODE_PICK_AUDIO) as T
|
||||
CONTACT -> ContactPicker(REQUEST_CODE_PICK_CONTACT) as T
|
||||
CAMERA -> CameraPicker(REQUEST_CODE_TAKE_PHOTO) as T
|
||||
else -> throw IllegalArgumentException("Unsupported type $type")
|
||||
IMAGE -> ImagePicker() as T
|
||||
VIDEO -> VideoPicker() as T
|
||||
FILE -> FilePicker() as T
|
||||
AUDIO -> AudioPicker() as T
|
||||
CONTACT -> ContactPicker() as T
|
||||
CAMERA -> CameraPicker() as T
|
||||
else -> throw IllegalArgumentException("Unsupported type $type")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,28 +16,25 @@
|
|||
|
||||
package im.vector.lib.multipicker
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.ResolveInfo
|
||||
import android.net.Uri
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
|
||||
/**
|
||||
* Abstract class to provide all types of Pickers
|
||||
*/
|
||||
abstract class Picker<T>(open val requestCode: Int) {
|
||||
abstract class Picker<T> {
|
||||
|
||||
protected var single = false
|
||||
|
||||
/**
|
||||
* Call this function from onActivityResult(int, int, Intent).
|
||||
* @return selected files or empty list if request code is wrong
|
||||
* or result code is not Activity.RESULT_OK
|
||||
* or user did not select any files.
|
||||
* @return selected files or empty list if user did not select any files.
|
||||
*/
|
||||
abstract fun getSelectedFiles(context: Context, requestCode: Int, resultCode: Int, data: Intent?): List<T>
|
||||
abstract fun getSelectedFiles(context: Context, data: Intent?): List<T>
|
||||
|
||||
/**
|
||||
* Use this function to retrieve files which are shared from another application or internally
|
||||
|
@ -61,7 +58,7 @@ abstract class Picker<T>(open val requestCode: Int) {
|
|||
context.grantUriPermission(packageName, it, Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
}
|
||||
}
|
||||
return getSelectedFiles(context, requestCode, Activity.RESULT_OK, data)
|
||||
return getSelectedFiles(context, data)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -75,19 +72,11 @@ abstract class Picker<T>(open val requestCode: Int) {
|
|||
abstract fun createIntent(): Intent
|
||||
|
||||
/**
|
||||
* Start Storage Access Framework UI by using an Activity.
|
||||
* @param activity Activity to handle onActivityResult().
|
||||
* Start Storage Access Framework UI by using a ActivityResultLauncher.
|
||||
* @param activityResultLauncher to handle the result.
|
||||
*/
|
||||
fun startWith(activity: Activity) {
|
||||
activity.startActivityForResult(createIntent().apply { addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) }, requestCode)
|
||||
}
|
||||
|
||||
/**
|
||||
* Start Storage Access Framework UI by using a Fragment.
|
||||
* @param fragment Fragment to handle onActivityResult().
|
||||
*/
|
||||
fun startWith(fragment: Fragment) {
|
||||
fragment.startActivityForResult(createIntent().apply { addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) }, requestCode)
|
||||
fun startWith(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||
activityResultLauncher.launch(createIntent().apply { addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) })
|
||||
}
|
||||
|
||||
protected fun getSelectedUriList(data: Intent?): List<Uri> {
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package im.vector.lib.multipicker
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.media.MediaMetadataRetriever
|
||||
|
@ -26,19 +25,13 @@ import im.vector.lib.multipicker.entity.MultiPickerVideoType
|
|||
/**
|
||||
* Video Picker implementation
|
||||
*/
|
||||
class VideoPicker(override val requestCode: Int) : Picker<MultiPickerVideoType>(requestCode) {
|
||||
class VideoPicker : Picker<MultiPickerVideoType>() {
|
||||
|
||||
/**
|
||||
* Call this function from onActivityResult(int, int, Intent).
|
||||
* Returns selected video files or empty list if request code is wrong
|
||||
* or result code is not Activity.RESULT_OK
|
||||
* or user did not select any files.
|
||||
* Returns selected video files or empty list if user did not select any files.
|
||||
*/
|
||||
override fun getSelectedFiles(context: Context, requestCode: Int, resultCode: Int, data: Intent?): List<MultiPickerVideoType> {
|
||||
if (requestCode != this.requestCode && resultCode != Activity.RESULT_OK) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override fun getSelectedFiles(context: Context, data: Intent?): List<MultiPickerVideoType> {
|
||||
val videoList = mutableListOf<MultiPickerVideoType>()
|
||||
|
||||
getSelectedUriList(data).forEach { selectedUri ->
|
||||
|
|
|
@ -280,22 +280,21 @@ android {
|
|||
|
||||
dependencies {
|
||||
|
||||
def epoxy_version = '3.11.0'
|
||||
def fragment_version = '1.2.5'
|
||||
def epoxy_version = '4.1.0'
|
||||
def fragment_version = '1.3.0-beta01'
|
||||
def arrow_version = "0.8.2"
|
||||
def coroutines_version = "1.3.8"
|
||||
def markwon_version = '4.1.2'
|
||||
def big_image_viewer_version = '1.6.2'
|
||||
def glide_version = '4.11.0'
|
||||
def moshi_version = '1.8.0'
|
||||
def daggerVersion = '2.25.4'
|
||||
def moshi_version = '1.11.0'
|
||||
def daggerVersion = '2.29.1'
|
||||
def autofill_version = "1.0.0"
|
||||
def work_version = '2.4.0'
|
||||
def arch_version = '2.1.0'
|
||||
def lifecycle_version = '2.2.0'
|
||||
|
||||
// Tests
|
||||
def kluent_version = '1.44'
|
||||
def kluent_version = '1.61'
|
||||
def androidxTest_version = '1.3.0'
|
||||
def espresso_version = '3.3.0'
|
||||
|
||||
|
@ -307,16 +306,16 @@ dependencies {
|
|||
implementation 'com.android.support:multidex:1.0.3'
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
|
||||
|
||||
implementation "androidx.recyclerview:recyclerview:1.2.0-alpha05"
|
||||
implementation "androidx.recyclerview:recyclerview:1.2.0-alpha06"
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation "androidx.fragment:fragment:$fragment_version"
|
||||
implementation "androidx.fragment:fragment-ktx:$fragment_version"
|
||||
// Keep at 2.0.0-beta4 at the moment, as updating is breaking some UI
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta4'
|
||||
implementation 'androidx.core:core-ktx:1.3.1'
|
||||
implementation 'androidx.core:core-ktx:1.3.2'
|
||||
|
||||
implementation "org.threeten:threetenbp:1.4.0:no-tzdb"
|
||||
implementation "com.gabrielittner.threetenbp:lazythreetenbp:0.7.0"
|
||||
|
@ -347,7 +346,7 @@ dependencies {
|
|||
implementation "com.airbnb.android:epoxy-glide-preloading:$epoxy_version"
|
||||
kapt "com.airbnb.android:epoxy-processor:$epoxy_version"
|
||||
implementation "com.airbnb.android:epoxy-paging:$epoxy_version"
|
||||
implementation 'com.airbnb.android:mvrx:1.3.0'
|
||||
implementation 'com.airbnb.android:mvrx:1.5.1'
|
||||
|
||||
// Work
|
||||
implementation "androidx.work:work-runtime-ktx:$work_version"
|
||||
|
@ -363,7 +362,7 @@ dependencies {
|
|||
|
||||
// UI
|
||||
implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
|
||||
implementation 'com.google.android.material:material:1.3.0-alpha01'
|
||||
implementation 'com.google.android.material:material:1.3.0-alpha02'
|
||||
implementation 'me.gujun.android:span:1.7'
|
||||
implementation "io.noties.markwon:core:$markwon_version"
|
||||
implementation "io.noties.markwon:html:$markwon_version"
|
||||
|
@ -398,7 +397,7 @@ dependencies {
|
|||
implementation "com.github.piasy:GlideImageViewFactory:$big_image_viewer_version"
|
||||
|
||||
// implementation 'com.github.MikeOrtiz:TouchImageView:3.0.2'
|
||||
implementation 'com.github.chrisbanes:PhotoView:2.0.0'
|
||||
implementation 'com.github.chrisbanes:PhotoView:2.1.4'
|
||||
|
||||
implementation "com.github.bumptech.glide:glide:$glide_version"
|
||||
kapt "com.github.bumptech.glide:compiler:$glide_version"
|
||||
|
@ -415,7 +414,7 @@ dependencies {
|
|||
kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.5.0'
|
||||
|
||||
// gplay flavor only
|
||||
gplayImplementation('com.google.firebase:firebase-messaging:20.2.4') {
|
||||
gplayImplementation('com.google.firebase:firebase-messaging:20.3.0') {
|
||||
exclude group: 'com.google.firebase', module: 'firebase-core'
|
||||
exclude group: 'com.google.firebase', module: 'firebase-analytics'
|
||||
exclude group: 'com.google.firebase', module: 'firebase-measurement-connector'
|
||||
|
@ -439,7 +438,7 @@ dependencies {
|
|||
implementation 'me.dm7.barcodescanner:zxing:1.9.13'
|
||||
|
||||
// TESTS
|
||||
testImplementation 'junit:junit:4.12'
|
||||
testImplementation 'junit:junit:4.13'
|
||||
testImplementation "org.amshove.kluent:kluent-android:$kluent_version"
|
||||
// Plant Timber tree for test
|
||||
testImplementation 'net.lachlanmckee:timber-junit-rule:1.0.1'
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
<issue id="DisableBaselineAlignment" severity="error" />
|
||||
<issue id="ScrollViewSize" severity="error" />
|
||||
<issue id="NegativeMargin" severity="error" />
|
||||
<issue id="UseCompatTextViewDrawableXml" severity="error" />
|
||||
|
||||
<!-- RTL -->
|
||||
<issue id="RtlEnabled" severity="error" />
|
||||
|
|
|
@ -28,6 +28,7 @@ import butterknife.OnClick
|
|||
import im.vector.app.R
|
||||
import im.vector.app.core.di.ActiveSessionHolder
|
||||
import im.vector.app.core.di.ScreenComponent
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
||||
import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA
|
||||
|
@ -196,33 +197,29 @@ class DebugMenuActivity : VectorBaseActivity() {
|
|||
}
|
||||
|
||||
private fun doScanQRCode() {
|
||||
QrCodeScannerActivity.startForResult(this)
|
||||
QrCodeScannerActivity.startForResult(this, qrStartForActivityResult)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
when (requestCode) {
|
||||
QrCodeScannerActivity.QR_CODE_SCANNER_REQUEST_CODE -> {
|
||||
toast("QrCode: " + QrCodeScannerActivity.getResultText(data) + " is QRCode: " + QrCodeScannerActivity.getResultIsQrCode(data))
|
||||
private val qrStartForActivityResult = registerStartForActivityResult { activityResult ->
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
toast("QrCode: " + QrCodeScannerActivity.getResultText(activityResult.data)
|
||||
+ " is QRCode: " + QrCodeScannerActivity.getResultIsQrCode(activityResult.data))
|
||||
|
||||
// Also update the current QR Code (reverse operation)
|
||||
// renderQrCode(QrCodeScannerActivity.getResultText(data) ?: "")
|
||||
val result = QrCodeScannerActivity.getResultText(data)!!
|
||||
// Also update the current QR Code (reverse operation)
|
||||
// renderQrCode(QrCodeScannerActivity.getResultText(data) ?: "")
|
||||
val result = QrCodeScannerActivity.getResultText(activityResult.data)!!
|
||||
|
||||
val qrCodeData = result.toQrCodeData()
|
||||
Timber.e("qrCodeData: $qrCodeData")
|
||||
val qrCodeData = result.toQrCodeData()
|
||||
Timber.e("qrCodeData: $qrCodeData")
|
||||
|
||||
if (result.length != buffer.size) {
|
||||
Timber.e("Error, length are not the same")
|
||||
} else {
|
||||
// Convert to ByteArray
|
||||
val byteArrayResult = result.toByteArray(Charsets.ISO_8859_1)
|
||||
for (i in byteArrayResult.indices) {
|
||||
if (buffer[i] != byteArrayResult[i]) {
|
||||
Timber.e("Error for byte $i, expecting ${buffer[i]} and get ${byteArrayResult[i]}")
|
||||
}
|
||||
}
|
||||
if (result.length != buffer.size) {
|
||||
Timber.e("Error, length are not the same")
|
||||
} else {
|
||||
// Convert to ByteArray
|
||||
val byteArrayResult = result.toByteArray(Charsets.ISO_8859_1)
|
||||
for (i in byteArrayResult.indices) {
|
||||
if (buffer[i] != byteArrayResult[i]) {
|
||||
Timber.e("Error for byte $i, expecting ${buffer[i]} and get ${byteArrayResult[i]}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package im.vector.app.fdroid.features.settings.troubleshoot
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
|
@ -28,7 +30,7 @@ class TestAutoStartBoot @Inject constructor(private val vectorPreferences: Vecto
|
|||
private val stringProvider: StringProvider)
|
||||
: TroubleshootTest(R.string.settings_troubleshoot_test_service_boot_title) {
|
||||
|
||||
override fun perform() {
|
||||
override fun perform(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||
if (vectorPreferences.autoStartOnBoot()) {
|
||||
description = stringProvider.getString(R.string.settings_troubleshoot_test_service_boot_success)
|
||||
status = TestStatus.SUCCESS
|
||||
|
@ -38,7 +40,7 @@ class TestAutoStartBoot @Inject constructor(private val vectorPreferences: Vecto
|
|||
quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_service_boot_quickfix) {
|
||||
override fun doFix() {
|
||||
vectorPreferences.setAutoStartOnBoot(true)
|
||||
manager?.retry()
|
||||
manager?.retry(activityResultLauncher)
|
||||
}
|
||||
}
|
||||
status = TestStatus.FAILED
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
*/
|
||||
package im.vector.app.fdroid.features.settings.troubleshoot
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.ConnectivityManager
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.net.ConnectivityManagerCompat
|
||||
|
@ -28,7 +30,7 @@ class TestBackgroundRestrictions @Inject constructor(private val context: AppCom
|
|||
private val stringProvider: StringProvider)
|
||||
: TroubleshootTest(R.string.settings_troubleshoot_test_bg_restricted_title) {
|
||||
|
||||
override fun perform() {
|
||||
override fun perform(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||
context.getSystemService<ConnectivityManager>()!!.apply {
|
||||
// Checks if the device is on a metered network
|
||||
if (isActiveNetworkMetered) {
|
||||
|
|
|
@ -15,12 +15,13 @@
|
|||
*/
|
||||
package im.vector.app.fdroid.features.settings.troubleshoot
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.core.utils.isIgnoringBatteryOptimizations
|
||||
import im.vector.app.core.utils.requestDisablingBatteryOptimization
|
||||
import im.vector.app.features.settings.troubleshoot.NotificationTroubleshootTestManager
|
||||
import im.vector.app.features.settings.troubleshoot.TroubleshootTest
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -29,7 +30,7 @@ class TestBatteryOptimization @Inject constructor(
|
|||
private val stringProvider: StringProvider
|
||||
) : TroubleshootTest(R.string.settings_troubleshoot_test_battery_title) {
|
||||
|
||||
override fun perform() {
|
||||
override fun perform(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||
if (isIgnoringBatteryOptimizations(context)) {
|
||||
description = stringProvider.getString(R.string.settings_troubleshoot_test_battery_success)
|
||||
status = TestStatus.SUCCESS
|
||||
|
@ -38,7 +39,7 @@ class TestBatteryOptimization @Inject constructor(
|
|||
description = stringProvider.getString(R.string.settings_troubleshoot_test_battery_failed)
|
||||
quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_battery_quickfix) {
|
||||
override fun doFix() {
|
||||
requestDisablingBatteryOptimization(context, null, NotificationTroubleshootTestManager.REQ_CODE_FIX)
|
||||
requestDisablingBatteryOptimization(context, activityResultLauncher)
|
||||
}
|
||||
}
|
||||
status = TestStatus.FAILED
|
||||
|
|
|
@ -15,12 +15,13 @@
|
|||
*/
|
||||
package im.vector.app.gplay.features.settings.troubleshoot
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.google.firebase.iid.FirebaseInstanceId
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.core.utils.startAddGoogleAccountIntent
|
||||
import im.vector.app.features.settings.troubleshoot.NotificationTroubleshootTestManager
|
||||
import im.vector.app.features.settings.troubleshoot.TroubleshootTest
|
||||
import im.vector.app.push.fcm.FcmHelper
|
||||
import timber.log.Timber
|
||||
|
@ -32,7 +33,7 @@ import javax.inject.Inject
|
|||
class TestFirebaseToken @Inject constructor(private val context: AppCompatActivity,
|
||||
private val stringProvider: StringProvider) : TroubleshootTest(R.string.settings_troubleshoot_test_fcm_title) {
|
||||
|
||||
override fun perform() {
|
||||
override fun perform(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||
status = TestStatus.RUNNING
|
||||
try {
|
||||
FirebaseInstanceId.getInstance().instanceId
|
||||
|
@ -48,7 +49,7 @@ class TestFirebaseToken @Inject constructor(private val context: AppCompatActivi
|
|||
description = stringProvider.getString(R.string.settings_troubleshoot_test_fcm_failed_account_missing, errorMsg)
|
||||
quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_fcm_failed_account_missing_quick_fix) {
|
||||
override fun doFix() {
|
||||
startAddGoogleAccountIntent(context, NotificationTroubleshootTestManager.REQ_CODE_FIX)
|
||||
startAddGoogleAccountIntent(context, activityResultLauncher)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package im.vector.app.gplay.features.settings.troubleshoot
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.google.android.gms.common.ConnectionResult
|
||||
import com.google.android.gms.common.GoogleApiAvailability
|
||||
|
@ -31,7 +33,7 @@ class TestPlayServices @Inject constructor(private val context: AppCompatActivit
|
|||
private val stringProvider: StringProvider)
|
||||
: TroubleshootTest(R.string.settings_troubleshoot_test_play_services_title) {
|
||||
|
||||
override fun perform() {
|
||||
override fun perform(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||
val apiAvailability = GoogleApiAvailability.getInstance()
|
||||
val resultCode = apiAvailability.isGooglePlayServicesAvailable(context)
|
||||
if (resultCode == ConnectionResult.SUCCESS) {
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package im.vector.app.gplay.features.settings.troubleshoot
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.work.WorkInfo
|
||||
|
@ -37,7 +39,7 @@ class TestTokenRegistration @Inject constructor(private val context: AppCompatAc
|
|||
private val activeSessionHolder: ActiveSessionHolder)
|
||||
: TroubleshootTest(R.string.settings_troubleshoot_test_token_registration_title) {
|
||||
|
||||
override fun perform() {
|
||||
override fun perform(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||
// Check if we have a registered pusher for this token
|
||||
val fcmToken = FcmHelper.getFcmToken(context) ?: run {
|
||||
status = TestStatus.FAILED
|
||||
|
@ -59,9 +61,9 @@ class TestTokenRegistration @Inject constructor(private val context: AppCompatAc
|
|||
WorkManager.getInstance(context).getWorkInfoByIdLiveData(workId).observe(context, Observer { workInfo ->
|
||||
if (workInfo != null) {
|
||||
if (workInfo.state == WorkInfo.State.SUCCEEDED) {
|
||||
manager?.retry()
|
||||
manager?.retry(activityResultLauncher)
|
||||
} else if (workInfo.state == WorkInfo.State.FAILED) {
|
||||
manager?.retry()
|
||||
manager?.retry(activityResultLauncher)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -232,9 +232,11 @@
|
|||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<!-- Add tools:ignore="Instantiatable" for the error reported only by Buildkite and for lintGplayRelease check :/ -->
|
||||
<service
|
||||
android:name=".core.services.VectorSyncService"
|
||||
android:exported="false" />
|
||||
android:exported="false"
|
||||
tools:ignore="Instantiatable" />
|
||||
|
||||
<service
|
||||
android:name=".features.call.telecom.VectorConnectionService"
|
||||
|
|
|
@ -17,11 +17,20 @@
|
|||
package im.vector.app.core.extensions
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Parcelable
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.result.ActivityResult
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
|
||||
fun ComponentActivity.registerStartForActivityResult(onResult: (ActivityResult) -> Unit): ActivityResultLauncher<Intent> {
|
||||
return registerForActivityResult(ActivityResultContracts.StartActivityForResult(), onResult)
|
||||
}
|
||||
|
||||
fun VectorBaseActivity.addFragment(
|
||||
frameId: Int,
|
||||
fragment: Fragment,
|
||||
|
|
|
@ -17,7 +17,11 @@
|
|||
package im.vector.app.core.extensions
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Parcelable
|
||||
import androidx.activity.result.ActivityResult
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.fragment.app.Fragment
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
|
@ -26,6 +30,10 @@ import java.text.SimpleDateFormat
|
|||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
fun Fragment.registerStartForActivityResult(onResult: (ActivityResult) -> Unit): ActivityResultLauncher<Intent> {
|
||||
return registerForActivityResult(ActivityResultContracts.StartActivityForResult(), onResult)
|
||||
}
|
||||
|
||||
fun VectorBaseFragment.addFragment(
|
||||
frameId: Int,
|
||||
fragment: Fragment,
|
||||
|
@ -160,26 +168,24 @@ fun Fragment.getAllChildFragments(): List<Fragment> {
|
|||
// Define a missing constant
|
||||
const val POP_BACK_STACK_EXCLUSIVE = 0
|
||||
|
||||
fun Fragment.queryExportKeys(userId: String, requestCode: Int) {
|
||||
fun Fragment.queryExportKeys(userId: String, activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||
val timestamp = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date())
|
||||
|
||||
selectTxtFileToWrite(
|
||||
activity = requireActivity(),
|
||||
fragment = this,
|
||||
activityResultLauncher = activityResultLauncher,
|
||||
defaultFileName = "element-megolm-export-$userId-$timestamp.txt",
|
||||
chooserHint = getString(R.string.keys_backup_setup_step1_manual_export),
|
||||
requestCode = requestCode
|
||||
chooserHint = getString(R.string.keys_backup_setup_step1_manual_export)
|
||||
)
|
||||
}
|
||||
|
||||
fun Activity.queryExportKeys(userId: String, requestCode: Int) {
|
||||
fun Activity.queryExportKeys(userId: String, activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||
val timestamp = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date())
|
||||
|
||||
selectTxtFileToWrite(
|
||||
activity = this,
|
||||
fragment = null,
|
||||
activityResultLauncher = activityResultLauncher,
|
||||
defaultFileName = "element-megolm-export-$userId-$timestamp.txt",
|
||||
chooserHint = getString(R.string.keys_backup_setup_step1_manual_export),
|
||||
requestCode = requestCode
|
||||
chooserHint = getString(R.string.keys_backup_setup_step1_manual_export)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ package im.vector.app.core.platform
|
|||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
|
@ -60,6 +59,7 @@ import im.vector.app.core.dialogs.UnrecognizedCertificateDialog
|
|||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.extensions.observeEvent
|
||||
import im.vector.app.core.extensions.observeNotNull
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.extensions.restart
|
||||
import im.vector.app.core.extensions.vectorComponent
|
||||
import im.vector.app.core.utils.toast
|
||||
|
@ -68,7 +68,6 @@ import im.vector.app.features.MainActivityArgs
|
|||
import im.vector.app.features.configuration.VectorConfiguration
|
||||
import im.vector.app.features.consent.ConsentNotGivenHelper
|
||||
import im.vector.app.features.navigation.Navigator
|
||||
import im.vector.app.features.pin.PinActivity
|
||||
import im.vector.app.features.pin.PinLocker
|
||||
import im.vector.app.features.pin.PinMode
|
||||
import im.vector.app.features.pin.UnlockedActivity
|
||||
|
@ -206,7 +205,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||
})
|
||||
pinLocker.getLiveState().observeNotNull(this) {
|
||||
if (this@VectorBaseActivity !is UnlockedActivity && it == PinLocker.State.LOCKED) {
|
||||
navigator.openPinCode(this, PinMode.AUTH)
|
||||
navigator.openPinCode(this, pinStartForActivityResult, PinMode.AUTH)
|
||||
}
|
||||
}
|
||||
sessionListener = vectorComponent.sessionListener()
|
||||
|
@ -313,22 +312,20 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||
uiDisposables.dispose()
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (requestCode == PinActivity.PIN_REQUEST_CODE) {
|
||||
when (resultCode) {
|
||||
Activity.RESULT_OK -> {
|
||||
Timber.v("Pin ok, unlock app")
|
||||
pinLocker.unlock()
|
||||
private val pinStartForActivityResult = registerStartForActivityResult { activityResult ->
|
||||
when (activityResult.resultCode) {
|
||||
Activity.RESULT_OK -> {
|
||||
Timber.v("Pin ok, unlock app")
|
||||
pinLocker.unlock()
|
||||
|
||||
// Cancel any new started PinActivity, after a screen rotation for instance
|
||||
finishActivity(PinActivity.PIN_REQUEST_CODE)
|
||||
}
|
||||
else -> {
|
||||
if (pinLocker.getLiveState().value != PinLocker.State.UNLOCKED) {
|
||||
// Remove the task, to be sure that PIN code will be requested when resumed
|
||||
finishAndRemoveTask()
|
||||
}
|
||||
// Cancel any new started PinActivity, after a screen rotation for instance
|
||||
// FIXME I cannot use this anymore :/
|
||||
// finishActivity(PinActivity.PIN_REQUEST_CODE)
|
||||
}
|
||||
else -> {
|
||||
if (pinLocker.getLiveState().value != PinLocker.State.UNLOCKED) {
|
||||
// Remove the task, to be sure that PIN code will be requested when resumed
|
||||
finishAndRemoveTask()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,9 +42,11 @@ abstract class VectorViewModel<S : MvRxState, VA : VectorViewModelAction, VE : V
|
|||
* This method does the same thing as the execute function, but it doesn't subscribe to the stream
|
||||
* so you can use this in a switchMap or a flatMap
|
||||
*/
|
||||
// False positive
|
||||
@Suppress("USELESS_CAST")
|
||||
fun <T> Single<T>.toAsync(stateReducer: S.(Async<T>) -> S): Single<Async<T>> {
|
||||
setState { stateReducer(Loading()) }
|
||||
return this.map { Success(it) as Async<T> }
|
||||
return map { Success(it) as Async<T> }
|
||||
.onErrorReturn { Fail(it) }
|
||||
.doOnSuccess { setState { stateReducer(it) } }
|
||||
}
|
||||
|
@ -53,9 +55,11 @@ abstract class VectorViewModel<S : MvRxState, VA : VectorViewModelAction, VE : V
|
|||
* This method does the same thing as the execute function, but it doesn't subscribe to the stream
|
||||
* so you can use this in a switchMap or a flatMap
|
||||
*/
|
||||
// False positive
|
||||
@Suppress("USELESS_CAST")
|
||||
fun <T> Observable<T>.toAsync(stateReducer: S.(Async<T>) -> S): Observable<Async<T>> {
|
||||
setState { stateReducer(Loading()) }
|
||||
return this.map { Success(it) as Async<T> }
|
||||
return map { Success(it) as Async<T> }
|
||||
.onErrorReturn { Fail(it) }
|
||||
.doOnNext { setState { stateReducer(it) } }
|
||||
}
|
||||
|
|
|
@ -31,12 +31,12 @@ import android.provider.Browser
|
|||
import android.provider.MediaStore
|
||||
import android.webkit.MimeTypeMap
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.browser.customtabs.CustomTabsIntent
|
||||
import androidx.browser.customtabs.CustomTabsSession
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.fragment.app.Fragment
|
||||
import im.vector.app.BuildConfig
|
||||
import im.vector.app.R
|
||||
import im.vector.app.features.notifications.NotificationUtils
|
||||
|
@ -130,7 +130,7 @@ fun openSoundRecorder(activity: Activity, requestCode: Int) {
|
|||
* Open file selection activity
|
||||
*/
|
||||
fun openFileSelection(activity: Activity,
|
||||
fragment: Fragment?,
|
||||
activityResultLauncher: ActivityResultLauncher<Intent>?,
|
||||
allowMultipleSelection: Boolean,
|
||||
requestCode: Int) {
|
||||
val fileIntent = Intent(Intent.ACTION_GET_CONTENT)
|
||||
|
@ -140,8 +140,8 @@ fun openFileSelection(activity: Activity,
|
|||
fileIntent.type = "*/*"
|
||||
|
||||
try {
|
||||
fragment
|
||||
?.startActivityForResult(fileIntent, requestCode)
|
||||
activityResultLauncher
|
||||
?.launch(fileIntent)
|
||||
?: run {
|
||||
activity.startActivityForResult(fileIntent, requestCode)
|
||||
}
|
||||
|
@ -440,10 +440,9 @@ fun openPlayStore(activity: Activity, appId: String = BuildConfig.APPLICATION_ID
|
|||
*/
|
||||
fun selectTxtFileToWrite(
|
||||
activity: Activity,
|
||||
fragment: Fragment?,
|
||||
activityResultLauncher: ActivityResultLauncher<Intent>,
|
||||
defaultFileName: String,
|
||||
chooserHint: String,
|
||||
requestCode: Int
|
||||
chooserHint: String
|
||||
) {
|
||||
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT)
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
|
@ -452,11 +451,7 @@ fun selectTxtFileToWrite(
|
|||
|
||||
try {
|
||||
val chooserIntent = Intent.createChooser(intent, chooserHint)
|
||||
if (fragment != null) {
|
||||
fragment.startActivityForResult(chooserIntent, requestCode)
|
||||
} else {
|
||||
activity.startActivityForResult(chooserIntent, requestCode)
|
||||
}
|
||||
activityResultLauncher.launch(chooserIntent)
|
||||
} catch (activityNotFoundException: ActivityNotFoundException) {
|
||||
activity.toast(R.string.error_no_external_application_found)
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ import android.content.Context
|
|||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.app.ActivityCompat
|
||||
|
@ -94,6 +96,12 @@ fun logPermissionStatuses(context: Context) {
|
|||
}
|
||||
}
|
||||
|
||||
fun Fragment.registerForPermissionsResult(allGranted: (Boolean) -> Unit): ActivityResultLauncher<Array<String>> {
|
||||
return registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { result ->
|
||||
allGranted.invoke(result.keys.all { result[it] == true })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See [.checkPermissions]
|
||||
*
|
||||
|
@ -112,14 +120,14 @@ fun checkPermissions(permissionsToBeGrantedBitMap: Int,
|
|||
* See [.checkPermissions]
|
||||
*
|
||||
* @param permissionsToBeGrantedBitMap
|
||||
* @param fragment
|
||||
* @param activityResultLauncher from the calling fragment that is requesting the permissions
|
||||
* @return true if the permissions are granted (synchronous flow), false otherwise (asynchronous flow)
|
||||
*/
|
||||
fun checkPermissions(permissionsToBeGrantedBitMap: Int,
|
||||
fragment: Fragment,
|
||||
requestCode: Int,
|
||||
activity: Activity,
|
||||
activityResultLauncher: ActivityResultLauncher<Array<String>>,
|
||||
@StringRes rationaleMessage: Int = 0): Boolean {
|
||||
return checkPermissions(permissionsToBeGrantedBitMap, fragment.activity, fragment, requestCode, rationaleMessage)
|
||||
return checkPermissions(permissionsToBeGrantedBitMap, activity, activityResultLauncher, 0, rationaleMessage)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -137,22 +145,19 @@ fun checkPermissions(permissionsToBeGrantedBitMap: Int,
|
|||
*
|
||||
* @param permissionsToBeGrantedBitMap the permissions bit map to be granted
|
||||
* @param activity the calling Activity that is requesting the permissions (or fragment parent)
|
||||
* @param fragment the calling fragment that is requesting the permissions
|
||||
* @param activityResultLauncher from the calling fragment that is requesting the permissions
|
||||
* @return true if the permissions are granted (synchronous flow), false otherwise (asynchronous flow)
|
||||
*/
|
||||
private fun checkPermissions(permissionsToBeGrantedBitMap: Int,
|
||||
activity: Activity?,
|
||||
fragment: Fragment?,
|
||||
activity: Activity,
|
||||
activityResultLauncher: ActivityResultLauncher<Array<String>>?,
|
||||
requestCode: Int,
|
||||
@StringRes rationaleMessage: Int
|
||||
): Boolean {
|
||||
var isPermissionGranted = false
|
||||
|
||||
// sanity check
|
||||
if (null == activity) {
|
||||
Timber.w("## checkPermissions(): invalid input data")
|
||||
isPermissionGranted = false
|
||||
} else if (PERMISSIONS_EMPTY == permissionsToBeGrantedBitMap) {
|
||||
if (PERMISSIONS_EMPTY == permissionsToBeGrantedBitMap) {
|
||||
isPermissionGranted = true
|
||||
} else if (PERMISSIONS_FOR_AUDIO_IP_CALL != permissionsToBeGrantedBitMap
|
||||
&& PERMISSIONS_FOR_VIDEO_IP_CALL != permissionsToBeGrantedBitMap
|
||||
|
@ -222,7 +227,8 @@ private fun checkPermissions(permissionsToBeGrantedBitMap: Int,
|
|||
.setOnCancelListener { Toast.makeText(activity, R.string.missing_permissions_warning, Toast.LENGTH_SHORT).show() }
|
||||
.setPositiveButton(R.string.ok) { _, _ ->
|
||||
if (permissionsListToBeGranted.isNotEmpty()) {
|
||||
fragment?.requestPermissions(permissionsListToBeGranted.toTypedArray(), requestCode)
|
||||
activityResultLauncher
|
||||
?.launch(permissionsListToBeGranted.toTypedArray())
|
||||
?: run {
|
||||
ActivityCompat.requestPermissions(activity, permissionsListToBeGranted.toTypedArray(), requestCode)
|
||||
}
|
||||
|
@ -262,7 +268,8 @@ private fun checkPermissions(permissionsToBeGrantedBitMap: Int,
|
|||
.show()
|
||||
*/
|
||||
} else {
|
||||
fragment?.requestPermissions(permissionsArrayToBeGranted, requestCode)
|
||||
activityResultLauncher
|
||||
?.launch(permissionsArrayToBeGranted)
|
||||
?: run {
|
||||
ActivityCompat.requestPermissions(activity, permissionsArrayToBeGranted, requestCode)
|
||||
}
|
||||
|
@ -307,43 +314,6 @@ private fun updatePermissionsToBeGranted(activity: Activity,
|
|||
return isRequestPermissionRequested
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to process [.PERMISSIONS_FOR_AUDIO_IP_CALL]
|
||||
* on onRequestPermissionsResult() methods.
|
||||
*
|
||||
* @param context App context
|
||||
* @param grantResults permissions granted results
|
||||
* @return true if audio IP call is permitted, false otherwise
|
||||
*/
|
||||
fun onPermissionResultAudioIpCall(context: Context, grantResults: IntArray): Boolean {
|
||||
val arePermissionsGranted = allGranted(grantResults)
|
||||
|
||||
if (!arePermissionsGranted) {
|
||||
Toast.makeText(context, R.string.permissions_action_not_performed_missing_permissions, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
return arePermissionsGranted
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to process [.PERMISSIONS_FOR_VIDEO_IP_CALL]
|
||||
* on onRequestPermissionsResult() methods.
|
||||
* For video IP calls, record audio and camera permissions are both mandatory.
|
||||
*
|
||||
* @param context App context
|
||||
* @param grantResults permissions granted results
|
||||
* @return true if video IP call is permitted, false otherwise
|
||||
*/
|
||||
fun onPermissionResultVideoIpCall(context: Context, grantResults: IntArray): Boolean {
|
||||
val arePermissionsGranted = allGranted(grantResults)
|
||||
|
||||
if (!arePermissionsGranted) {
|
||||
Toast.makeText(context, R.string.permissions_action_not_performed_missing_permissions, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
return arePermissionsGranted
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if all permissions are granted, false if not or if permission request has been cancelled
|
||||
*/
|
||||
|
|
|
@ -28,6 +28,7 @@ import android.os.Build
|
|||
import android.os.PowerManager
|
||||
import android.provider.Settings
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.getSystemService
|
||||
|
@ -67,15 +68,11 @@ fun isAnimationDisabled(context: Context): Boolean {
|
|||
* will return false and the notification privacy will fallback to "LOW_DETAIL".
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
fun requestDisablingBatteryOptimization(activity: Activity, fragment: Fragment?, requestCode: Int) {
|
||||
fun requestDisablingBatteryOptimization(activity: Activity, activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||
val intent = Intent()
|
||||
intent.action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
|
||||
intent.data = Uri.parse("package:" + activity.packageName)
|
||||
if (fragment != null) {
|
||||
fragment.startActivityForResult(intent, requestCode)
|
||||
} else {
|
||||
activity.startActivityForResult(intent, requestCode)
|
||||
}
|
||||
activityResultLauncher.launch(intent)
|
||||
}
|
||||
|
||||
// ==============================================================================================================
|
||||
|
@ -100,7 +97,7 @@ fun copyToClipboard(context: Context, text: CharSequence, showToast: Boolean = t
|
|||
* Shows notification settings for the current app.
|
||||
* In android O will directly opens the notification settings, in lower version it will show the App settings
|
||||
*/
|
||||
fun startNotificationSettingsIntent(activity: AppCompatActivity, requestCode: Int) {
|
||||
fun startNotificationSettingsIntent(activity: AppCompatActivity, activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||
val intent = Intent()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
intent.action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
|
||||
|
@ -110,7 +107,7 @@ fun startNotificationSettingsIntent(activity: AppCompatActivity, requestCode: In
|
|||
intent.putExtra("app_package", activity.packageName)
|
||||
intent.putExtra("app_uid", activity.applicationInfo?.uid)
|
||||
}
|
||||
activity.startActivityForResult(intent, requestCode)
|
||||
activityResultLauncher.launch(intent)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -126,42 +123,47 @@ fun startNotificationChannelSettingsIntent(fragment: Fragment, channelID: String
|
|||
fragment.startActivity(intent)
|
||||
}
|
||||
|
||||
fun startAddGoogleAccountIntent(context: AppCompatActivity, requestCode: Int) {
|
||||
fun startAddGoogleAccountIntent(context: Context, activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||
try {
|
||||
val intent = Intent(Settings.ACTION_ADD_ACCOUNT)
|
||||
intent.putExtra(Settings.EXTRA_ACCOUNT_TYPES, arrayOf("com.google"))
|
||||
context.startActivityForResult(intent, requestCode)
|
||||
activityResultLauncher.launch(intent)
|
||||
} catch (activityNotFoundException: ActivityNotFoundException) {
|
||||
context.toast(R.string.error_no_external_application_found)
|
||||
}
|
||||
}
|
||||
|
||||
fun startSharePlainTextIntent(fragment: Fragment, chooserTitle: String?, text: String, subject: String? = null, requestCode: Int? = null) {
|
||||
fun startSharePlainTextIntent(fragment: Fragment,
|
||||
activityResultLauncher: ActivityResultLauncher<Intent>?,
|
||||
chooserTitle: String?,
|
||||
text: String,
|
||||
subject: String? = null) {
|
||||
val share = Intent(Intent.ACTION_SEND)
|
||||
share.type = "text/plain"
|
||||
share.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT)
|
||||
// Add data to the intent, the receiving app will decide what to do with it.
|
||||
share.putExtra(Intent.EXTRA_SUBJECT, subject)
|
||||
share.putExtra(Intent.EXTRA_TEXT, text)
|
||||
val intent = Intent.createChooser(share, chooserTitle)
|
||||
try {
|
||||
if (requestCode != null) {
|
||||
fragment.startActivityForResult(Intent.createChooser(share, chooserTitle), requestCode)
|
||||
if (activityResultLauncher != null) {
|
||||
activityResultLauncher.launch(intent)
|
||||
} else {
|
||||
fragment.startActivity(Intent.createChooser(share, chooserTitle))
|
||||
fragment.startActivity(intent)
|
||||
}
|
||||
} catch (activityNotFoundException: ActivityNotFoundException) {
|
||||
fragment.activity?.toast(R.string.error_no_external_application_found)
|
||||
}
|
||||
}
|
||||
|
||||
fun startImportTextFromFileIntent(fragment: Fragment, requestCode: Int) {
|
||||
fun startImportTextFromFileIntent(context: Context, activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||
val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
|
||||
type = "text/plain"
|
||||
}
|
||||
if (intent.resolveActivity(fragment.requireActivity().packageManager) != null) {
|
||||
fragment.startActivityForResult(intent, requestCode)
|
||||
if (intent.resolveActivity(context.packageManager) != null) {
|
||||
activityResultLauncher.launch(intent)
|
||||
} else {
|
||||
fragment.activity?.toast(R.string.error_no_external_application_found)
|
||||
context.toast(R.string.error_no_external_application_found)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,12 +15,11 @@
|
|||
*/
|
||||
package im.vector.app.features.attachments
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import im.vector.app.core.platform.Restorable
|
||||
import im.vector.lib.multipicker.MultiPicker
|
||||
import org.matrix.android.sdk.BuildConfig
|
||||
|
@ -48,6 +47,7 @@ class AttachmentsHelper(val context: Context, val callback: Callback) : Restorab
|
|||
|
||||
// Capture path allows to handle camera image picking. It must be restored if the activity gets killed.
|
||||
private var captureUri: Uri? = null
|
||||
|
||||
// The pending type is set if we have to handle permission request. It must be restored if the activity gets killed.
|
||||
var pendingType: AttachmentTypeSelectorView.Type? = null
|
||||
|
||||
|
@ -72,99 +72,93 @@ class AttachmentsHelper(val context: Context, val callback: Callback) : Restorab
|
|||
/**
|
||||
* Starts the process for handling file picking
|
||||
*/
|
||||
fun selectFile(fragment: Fragment) {
|
||||
MultiPicker.get(MultiPicker.FILE).startWith(fragment)
|
||||
fun selectFile(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||
MultiPicker.get(MultiPicker.FILE).startWith(activityResultLauncher)
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the process for handling image picking
|
||||
*/
|
||||
fun selectGallery(fragment: Fragment) {
|
||||
MultiPicker.get(MultiPicker.IMAGE).startWith(fragment)
|
||||
fun selectGallery(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||
MultiPicker.get(MultiPicker.IMAGE).startWith(activityResultLauncher)
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the process for handling audio picking
|
||||
*/
|
||||
fun selectAudio(fragment: Fragment) {
|
||||
MultiPicker.get(MultiPicker.AUDIO).startWith(fragment)
|
||||
fun selectAudio(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||
MultiPicker.get(MultiPicker.AUDIO).startWith(activityResultLauncher)
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the process for handling capture image picking
|
||||
*/
|
||||
fun openCamera(fragment: Fragment) {
|
||||
captureUri = MultiPicker.get(MultiPicker.CAMERA).startWithExpectingFile(fragment)
|
||||
fun openCamera(context: Context, activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||
captureUri = MultiPicker.get(MultiPicker.CAMERA).startWithExpectingFile(context, activityResultLauncher)
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the process for handling contact picking
|
||||
*/
|
||||
fun selectContact(fragment: Fragment) {
|
||||
MultiPicker.get(MultiPicker.CONTACT).startWith(fragment)
|
||||
fun selectContact(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||
MultiPicker.get(MultiPicker.CONTACT).startWith(activityResultLauncher)
|
||||
}
|
||||
|
||||
/**
|
||||
* This methods aims to handle on activity result data.
|
||||
*
|
||||
* @return true if it can handle the data, false otherwise
|
||||
* This methods aims to handle the result data.
|
||||
*/
|
||||
fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
when (requestCode) {
|
||||
MultiPicker.REQUEST_CODE_PICK_FILE -> {
|
||||
callback.onContentAttachmentsReady(
|
||||
MultiPicker.get(MultiPicker.FILE)
|
||||
.getSelectedFiles(context, requestCode, resultCode, data)
|
||||
.map { it.toContentAttachmentData() }
|
||||
)
|
||||
fun onFileResult(data: Intent?) {
|
||||
callback.onContentAttachmentsReady(
|
||||
MultiPicker.get(MultiPicker.FILE)
|
||||
.getSelectedFiles(context, data)
|
||||
.map { it.toContentAttachmentData() }
|
||||
)
|
||||
}
|
||||
|
||||
fun onAudioResult(data: Intent?) {
|
||||
callback.onContentAttachmentsReady(
|
||||
MultiPicker.get(MultiPicker.AUDIO)
|
||||
.getSelectedFiles(context, data)
|
||||
.map { it.toContentAttachmentData() }
|
||||
)
|
||||
}
|
||||
|
||||
fun onContactResult(data: Intent?) {
|
||||
MultiPicker.get(MultiPicker.CONTACT)
|
||||
.getSelectedFiles(context, data)
|
||||
.firstOrNull()
|
||||
?.toContactAttachment()
|
||||
?.let {
|
||||
callback.onContactAttachmentReady(it)
|
||||
}
|
||||
MultiPicker.REQUEST_CODE_PICK_AUDIO -> {
|
||||
callback.onContentAttachmentsReady(
|
||||
MultiPicker.get(MultiPicker.AUDIO)
|
||||
.getSelectedFiles(context, requestCode, resultCode, data)
|
||||
.map { it.toContentAttachmentData() }
|
||||
)
|
||||
}
|
||||
MultiPicker.REQUEST_CODE_PICK_CONTACT -> {
|
||||
MultiPicker.get(MultiPicker.CONTACT)
|
||||
.getSelectedFiles(context, requestCode, resultCode, data)
|
||||
.firstOrNull()
|
||||
?.toContactAttachment()
|
||||
?.let {
|
||||
callback.onContactAttachmentReady(it)
|
||||
}
|
||||
}
|
||||
MultiPicker.REQUEST_CODE_PICK_IMAGE -> {
|
||||
callback.onContentAttachmentsReady(
|
||||
MultiPicker.get(MultiPicker.IMAGE)
|
||||
.getSelectedFiles(context, requestCode, resultCode, data)
|
||||
.map { it.toContentAttachmentData() }
|
||||
)
|
||||
}
|
||||
MultiPicker.REQUEST_CODE_TAKE_PHOTO -> {
|
||||
captureUri?.let { captureUri ->
|
||||
MultiPicker.get(MultiPicker.CAMERA)
|
||||
.getTakenPhoto(context, requestCode, resultCode, captureUri)
|
||||
?.let {
|
||||
callback.onContentAttachmentsReady(
|
||||
listOf(it).map { it.toContentAttachmentData() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun onImageResult(data: Intent?) {
|
||||
callback.onContentAttachmentsReady(
|
||||
MultiPicker.get(MultiPicker.IMAGE)
|
||||
.getSelectedFiles(context, data)
|
||||
.map { it.toContentAttachmentData() }
|
||||
)
|
||||
}
|
||||
|
||||
fun onPhotoResult() {
|
||||
captureUri?.let { captureUri ->
|
||||
MultiPicker.get(MultiPicker.CAMERA)
|
||||
.getTakenPhoto(context, captureUri)
|
||||
?.let {
|
||||
callback.onContentAttachmentsReady(
|
||||
listOf(it).map { it.toContentAttachmentData() }
|
||||
)
|
||||
}
|
||||
}
|
||||
MultiPicker.REQUEST_CODE_PICK_VIDEO -> {
|
||||
callback.onContentAttachmentsReady(
|
||||
MultiPicker.get(MultiPicker.VIDEO)
|
||||
.getSelectedFiles(context, requestCode, resultCode, data)
|
||||
.map { it.toContentAttachmentData() }
|
||||
)
|
||||
}
|
||||
else -> return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun onVideoResult(data: Intent?) {
|
||||
callback.onContentAttachmentsReady(
|
||||
MultiPicker.get(MultiPicker.VIDEO)
|
||||
.getSelectedFiles(context, data)
|
||||
.map { it.toContentAttachmentData() }
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -30,8 +30,6 @@ import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
|||
class AttachmentsPreviewActivity : VectorBaseActivity(), ToolbarConfigurable {
|
||||
|
||||
companion object {
|
||||
const val REQUEST_CODE = 55
|
||||
|
||||
private const val EXTRA_FRAGMENT_ARGS = "EXTRA_FRAGMENT_ARGS"
|
||||
private const val ATTACHMENTS_PREVIEW_RESULT = "ATTACHMENTS_PREVIEW_RESULT"
|
||||
private const val KEEP_ORIGINAL_IMAGES_SIZE = "KEEP_ORIGINAL_IMAGES_SIZE"
|
||||
|
|
|
@ -81,6 +81,10 @@ class AttachmentsPreviewFragment @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
// TODO handle this one (Ucrop lib)
|
||||
@Suppress("DEPRECATION")
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
|
||||
if (resultCode == RESULT_OK) {
|
||||
if (requestCode == UCrop.REQUEST_CROP && data != null) {
|
||||
Timber.v("Crop success")
|
||||
|
|
|
@ -298,6 +298,7 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis
|
|||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
if (requestCode == CAPTURE_PERMISSION_REQUEST_CODE && allGranted(grantResults)) {
|
||||
start()
|
||||
} else {
|
||||
|
|
|
@ -150,6 +150,7 @@ class VectorJitsiActivity : VectorBaseActivity(), JitsiMeetActivityInterface, Ji
|
|||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
JitsiMeetActivityDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
}
|
||||
|
||||
|
|
|
@ -111,6 +111,7 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() {
|
|||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
if (allGranted(grantResults)) {
|
||||
if (requestCode == PERMISSION_REQUEST_CODE_READ_CONTACTS) {
|
||||
doOnPostResume { addFragmentToBackstack(R.id.container, ContactsBookFragment::class.java) }
|
||||
|
|
|
@ -23,6 +23,7 @@ import androidx.lifecycle.Observer
|
|||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.addFragmentToBackstack
|
||||
import im.vector.app.core.extensions.observeEvent
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.extensions.replaceFragment
|
||||
import im.vector.app.core.platform.SimpleFragmentActivity
|
||||
import im.vector.app.core.ui.views.KeysBackupBanner
|
||||
|
@ -32,8 +33,6 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_S
|
|||
class KeysBackupRestoreActivity : SimpleFragmentActivity() {
|
||||
|
||||
companion object {
|
||||
|
||||
private const val REQUEST_4S_SECRET = 100
|
||||
const val SECRET_ALIAS = SharedSecureStorageActivity.DEFAULT_RESULT_KEYSTORE_ALIAS
|
||||
|
||||
fun intent(context: Context): Intent {
|
||||
|
@ -130,22 +129,19 @@ class KeysBackupRestoreActivity : SimpleFragmentActivity() {
|
|||
requestedSecrets = listOf(KEYBACKUP_SECRET_SSSS_NAME),
|
||||
resultKeyStoreAlias = SECRET_ALIAS
|
||||
).let {
|
||||
startActivityForResult(it, REQUEST_4S_SECRET)
|
||||
secretStartForActivityResult.launch(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == REQUEST_4S_SECRET) {
|
||||
val extraResult = data?.getStringExtra(SharedSecureStorageActivity.EXTRA_DATA_RESULT)
|
||||
if (resultCode == Activity.RESULT_OK && extraResult != null) {
|
||||
viewModel.handleGotSecretFromSSSS(
|
||||
extraResult,
|
||||
SECRET_ALIAS
|
||||
)
|
||||
} else {
|
||||
finish()
|
||||
}
|
||||
private val secretStartForActivityResult = registerStartForActivityResult { activityResult ->
|
||||
val extraResult = activityResult.data?.getStringExtra(SharedSecureStorageActivity.EXTRA_DATA_RESULT)
|
||||
if (activityResult.resultCode == Activity.RESULT_OK && extraResult != null) {
|
||||
viewModel.handleGotSecretFromSSSS(
|
||||
extraResult,
|
||||
SECRET_ALIAS
|
||||
)
|
||||
} else {
|
||||
finish()
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
package im.vector.app.features.crypto.keysbackup.restore
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.view.View
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.widget.EditText
|
||||
import androidx.lifecycle.Observer
|
||||
|
@ -27,19 +27,15 @@ import butterknife.OnClick
|
|||
import butterknife.OnTextChanged
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.utils.startImportTextFromFileIntent
|
||||
import timber.log.Timber
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import javax.inject.Inject
|
||||
|
||||
class KeysBackupRestoreFromKeyFragment @Inject constructor()
|
||||
: VectorBaseFragment() {
|
||||
|
||||
companion object {
|
||||
|
||||
private const val REQUEST_TEXT_FILE_GET = 1
|
||||
}
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_keys_backup_restore_from_key
|
||||
|
||||
private lateinit var viewModel: KeysBackupRestoreFromKeyViewModel
|
||||
|
@ -47,11 +43,12 @@ class KeysBackupRestoreFromKeyFragment @Inject constructor()
|
|||
|
||||
@BindView(R.id.keys_backup_key_enter_til)
|
||||
lateinit var mKeyInputLayout: TextInputLayout
|
||||
|
||||
@BindView(R.id.keys_restore_key_enter_edittext)
|
||||
lateinit var mKeyTextEdit: EditText
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
viewModel = fragmentViewModelProvider.get(KeysBackupRestoreFromKeyViewModel::class.java)
|
||||
sharedViewModel = activityViewModelProvider.get(KeysBackupRestoreSharedViewModel::class.java)
|
||||
mKeyTextEdit.setText(viewModel.recoveryCode.value)
|
||||
|
@ -88,29 +85,23 @@ class KeysBackupRestoreFromKeyFragment @Inject constructor()
|
|||
|
||||
@OnClick(R.id.keys_backup_import)
|
||||
fun onImport() {
|
||||
startImportTextFromFileIntent(this, REQUEST_TEXT_FILE_GET)
|
||||
startImportTextFromFileIntent(requireContext(), textFileStartForActivityResult)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == REQUEST_TEXT_FILE_GET && resultCode == Activity.RESULT_OK) {
|
||||
val dataURI = data?.data
|
||||
if (dataURI != null) {
|
||||
try {
|
||||
activity
|
||||
?.contentResolver
|
||||
?.openInputStream(dataURI)
|
||||
?.bufferedReader()
|
||||
?.use { it.readText() }
|
||||
?.let {
|
||||
mKeyTextEdit.setText(it)
|
||||
mKeyTextEdit.setSelection(it.length)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Failed to read recovery kay from text")
|
||||
}
|
||||
private val textFileStartForActivityResult = registerStartForActivityResult { activityResult ->
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
val dataURI = activityResult.data?.data ?: return@registerStartForActivityResult
|
||||
tryOrNull(message = "Failed to read recovery kay from text") {
|
||||
activity
|
||||
?.contentResolver
|
||||
?.openInputStream(dataURI)
|
||||
?.bufferedReader()
|
||||
?.use { it.readText() }
|
||||
?.let {
|
||||
mKeyTextEdit.setText(it)
|
||||
mKeyTextEdit.setSelection(it.length)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,8 +59,8 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase
|
|||
viewModel.showPasswordMode.value = !(viewModel.showPasswordMode.value ?: false)
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
viewModel = fragmentViewModelProvider.get(KeysBackupRestoreFromPassphraseViewModel::class.java)
|
||||
sharedViewModel = activityViewModelProvider.get(KeysBackupRestoreSharedViewModel::class.java)
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package im.vector.app.features.crypto.keysbackup.restore
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.isVisible
|
||||
import butterknife.BindView
|
||||
|
@ -36,8 +37,8 @@ class KeysBackupRestoreSuccessFragment @Inject constructor() : VectorBaseFragmen
|
|||
|
||||
private lateinit var sharedViewModel: KeysBackupRestoreSharedViewModel
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
sharedViewModel = activityViewModelProvider.get(KeysBackupRestoreSharedViewModel::class.java)
|
||||
|
||||
if (compareValues(sharedViewModel.importKeyResult?.totalNumberOfKeys, 0) > 0) {
|
||||
|
|
|
@ -26,6 +26,7 @@ import im.vector.app.R
|
|||
import im.vector.app.core.dialogs.ExportKeysDialog
|
||||
import im.vector.app.core.extensions.observeEvent
|
||||
import im.vector.app.core.extensions.queryExportKeys
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.extensions.replaceFragment
|
||||
import im.vector.app.core.platform.SimpleFragmentActivity
|
||||
import im.vector.app.core.utils.toast
|
||||
|
@ -93,7 +94,7 @@ class KeysBackupSetupActivity : SimpleFragmentActivity() {
|
|||
.show()
|
||||
}
|
||||
KeysBackupSetupSharedViewModel.NAVIGATE_MANUAL_EXPORT -> {
|
||||
queryExportKeys(session.myUserId, REQUEST_CODE_SAVE_MEGOLM_EXPORT)
|
||||
queryExportKeys(session.myUserId, saveStartForActivityResult)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -125,10 +126,10 @@ class KeysBackupSetupActivity : SimpleFragmentActivity() {
|
|||
})
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == REQUEST_CODE_SAVE_MEGOLM_EXPORT) {
|
||||
val uri = data?.data
|
||||
if (resultCode == Activity.RESULT_OK && uri != null) {
|
||||
private val saveStartForActivityResult = registerStartForActivityResult { activityResult ->
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
val uri = activityResult.data?.data
|
||||
if (uri != null) {
|
||||
ExportKeysDialog().show(this, object : ExportKeysDialog.ExportKeyDialogListener {
|
||||
override fun onPassphrase(passphrase: String) {
|
||||
showWaitingView()
|
||||
|
@ -163,7 +164,6 @@ class KeysBackupSetupActivity : SimpleFragmentActivity() {
|
|||
hideWaitingView()
|
||||
}
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
|
@ -198,7 +198,6 @@ class KeysBackupSetupActivity : SimpleFragmentActivity() {
|
|||
const val KEYS_VERSION = "KEYS_VERSION"
|
||||
const val MANUAL_EXPORT = "MANUAL_EXPORT"
|
||||
const val EXTRA_SHOW_MANUAL_EXPORT = "SHOW_MANUAL_EXPORT"
|
||||
const val REQUEST_CODE_SAVE_MEGOLM_EXPORT = 101
|
||||
|
||||
fun intent(context: Context, showManualExport: Boolean): Intent {
|
||||
val intent = Intent(context, KeysBackupSetupActivity::class.java)
|
||||
|
|
|
@ -40,8 +40,8 @@ class KeysBackupSetupStep1Fragment @Inject constructor() : VectorBaseFragment()
|
|||
@BindView(R.id.keys_backup_setup_step1_manualExport)
|
||||
lateinit var manualExportButton: Button
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
viewModel = activityViewModelProvider.get(KeysBackupSetupSharedViewModel::class.java)
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package im.vector.app.features.crypto.keysbackup.setup
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.widget.EditText
|
||||
|
@ -77,8 +78,8 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment()
|
|||
|
||||
private lateinit var viewModel: KeysBackupSetupSharedViewModel
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
viewModel = activityViewModelProvider.get(KeysBackupSetupSharedViewModel::class.java)
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
package im.vector.app.features.crypto.keysbackup.setup
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
|
@ -31,6 +30,7 @@ import butterknife.BindView
|
|||
import butterknife.OnClick
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.utils.LiveEvent
|
||||
import im.vector.app.core.utils.copyToClipboard
|
||||
|
@ -48,10 +48,6 @@ import javax.inject.Inject
|
|||
|
||||
class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment() {
|
||||
|
||||
companion object {
|
||||
private const val SAVE_RECOVERY_KEY_REQUEST_CODE = 2754
|
||||
}
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_keys_backup_setup_step3
|
||||
|
||||
@BindView(R.id.keys_backup_setup_step3_button)
|
||||
|
@ -65,8 +61,8 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment()
|
|||
|
||||
private lateinit var viewModel: KeysBackupSetupSharedViewModel
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
viewModel = activityViewModelProvider.get(KeysBackupSetupSharedViewModel::class.java)
|
||||
|
||||
viewModel.shouldPromptOnBack = false
|
||||
|
@ -138,19 +134,20 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment()
|
|||
val timestamp = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date())
|
||||
selectTxtFileToWrite(
|
||||
activity = requireActivity(),
|
||||
fragment = this,
|
||||
activityResultLauncher = saveRecoveryActivityResultLauncher,
|
||||
defaultFileName = "recovery-key-$userId-$timestamp.txt",
|
||||
chooserHint = getString(R.string.save_recovery_key_chooser_hint),
|
||||
requestCode = SAVE_RECOVERY_KEY_REQUEST_CODE
|
||||
chooserHint = getString(R.string.save_recovery_key_chooser_hint)
|
||||
)
|
||||
dialog.dismiss()
|
||||
}
|
||||
|
||||
dialog.findViewById<View>(R.id.keys_backup_setup_share)?.setOnClickListener {
|
||||
startSharePlainTextIntent(this,
|
||||
context?.getString(R.string.keys_backup_setup_step3_share_intent_chooser_title),
|
||||
recoveryKey,
|
||||
context?.getString(R.string.recovery_key))
|
||||
startSharePlainTextIntent(
|
||||
fragment = this,
|
||||
activityResultLauncher = null,
|
||||
chooserTitle = context?.getString(R.string.keys_backup_setup_step3_share_intent_chooser_title),
|
||||
text = recoveryKey,
|
||||
subject = context?.getString(R.string.recovery_key))
|
||||
viewModel.copyHasBeenMade = true
|
||||
dialog.dismiss()
|
||||
}
|
||||
|
@ -202,15 +199,11 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment()
|
|||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
when (requestCode) {
|
||||
SAVE_RECOVERY_KEY_REQUEST_CODE -> {
|
||||
val uri = data?.data
|
||||
if (resultCode == Activity.RESULT_OK && uri != null) {
|
||||
viewModel.recoveryKey.value?.let {
|
||||
exportRecoveryKeyToFile(uri, it)
|
||||
}
|
||||
}
|
||||
private val saveRecoveryActivityResultLauncher = registerStartForActivityResult { activityRessult ->
|
||||
val uri = activityRessult.data?.data ?: return@registerStartForActivityResult
|
||||
if (activityRessult.resultCode == Activity.RESULT_OK) {
|
||||
viewModel.recoveryKey.value?.let {
|
||||
exportRecoveryKeyToFile(uri, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@ class KeyRequestHandler @Inject constructor(
|
|||
// can we get more info on this device?
|
||||
session?.cryptoService()?.getMyDevicesInfo()?.firstOrNull { it.deviceId == deviceId }?.let {
|
||||
postAlert(context, userId, deviceId, true, deviceInfo, it)
|
||||
} ?: kotlin.run {
|
||||
} ?: run {
|
||||
postAlert(context, userId, deviceId, true, deviceInfo)
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -24,6 +24,8 @@ import android.os.Parcelable
|
|||
import android.view.View
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.FragmentOnAttachListener
|
||||
import com.airbnb.mvrx.MvRx
|
||||
import com.airbnb.mvrx.viewModel
|
||||
import im.vector.app.R
|
||||
|
@ -38,7 +40,10 @@ import kotlinx.android.synthetic.main.activity.*
|
|||
import javax.inject.Inject
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
class SharedSecureStorageActivity : SimpleFragmentActivity(), VectorBaseBottomSheetDialogFragment.ResultListener {
|
||||
class SharedSecureStorageActivity :
|
||||
SimpleFragmentActivity(),
|
||||
VectorBaseBottomSheetDialogFragment.ResultListener,
|
||||
FragmentOnAttachListener {
|
||||
|
||||
@Parcelize
|
||||
data class Args(
|
||||
|
@ -58,6 +63,8 @@ class SharedSecureStorageActivity : SimpleFragmentActivity(), VectorBaseBottomSh
|
|||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
supportFragmentManager.addFragmentOnAttachListener(this)
|
||||
|
||||
toolbar.visibility = View.GONE
|
||||
|
||||
viewModel.observeViewEvents { observeViewEvents(it) }
|
||||
|
@ -65,6 +72,11 @@ class SharedSecureStorageActivity : SimpleFragmentActivity(), VectorBaseBottomSh
|
|||
viewModel.subscribe(this) { renderState(it) }
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
supportFragmentManager.removeFragmentOnAttachListener(this)
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
viewModel.handle(SharedSecureStorageAction.Back)
|
||||
}
|
||||
|
@ -119,8 +131,7 @@ class SharedSecureStorageActivity : SimpleFragmentActivity(), VectorBaseBottomSh
|
|||
}
|
||||
}
|
||||
|
||||
override fun onAttachFragment(fragment: Fragment) {
|
||||
super.onAttachFragment(fragment)
|
||||
override fun onAttachFragment(fragmentManager: FragmentManager, fragment: Fragment) {
|
||||
if (fragment is VectorBaseBottomSheetDialogFragment) {
|
||||
fragment.resultListener = this
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package im.vector.app.features.crypto.quads
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.inputmethod.EditorInfo
|
||||
|
@ -25,6 +24,7 @@ import com.airbnb.mvrx.activityViewModel
|
|||
import com.jakewharton.rxbinding3.widget.editorActionEvents
|
||||
import com.jakewharton.rxbinding3.widget.textChanges
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.utils.startImportTextFromFileIntent
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
|
@ -61,7 +61,7 @@ class SharedSecuredStorageKeyFragment @Inject constructor() : VectorBaseFragment
|
|||
}
|
||||
.disposeOnDestroyView()
|
||||
|
||||
ssss_key_use_file.debouncedClicks { startImportTextFromFileIntent(this, IMPORT_FILE_REQ) }
|
||||
ssss_key_use_file.debouncedClicks { startImportTextFromFileIntent(requireContext(), importFileStartForActivityResult) }
|
||||
|
||||
ssss_key_reset.clickableView.debouncedClicks {
|
||||
sharedViewModel.handle(SharedSecureStorageAction.ForgotResetAll)
|
||||
|
@ -85,9 +85,9 @@ class SharedSecuredStorageKeyFragment @Inject constructor() : VectorBaseFragment
|
|||
sharedViewModel.handle(SharedSecureStorageAction.SubmitKey(text))
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == IMPORT_FILE_REQ && resultCode == Activity.RESULT_OK) {
|
||||
data?.data?.let { dataURI ->
|
||||
private val importFileStartForActivityResult = registerStartForActivityResult { activityResult ->
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
activityResult.data?.data?.let { dataURI ->
|
||||
tryOrNull {
|
||||
activity?.contentResolver?.openInputStream(dataURI)
|
||||
?.bufferedReader()
|
||||
|
@ -97,12 +97,6 @@ class SharedSecuredStorageKeyFragment @Inject constructor() : VectorBaseFragment
|
|||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val IMPORT_FILE_REQ = 0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -139,7 +139,7 @@ class BootstrapCrossSigningTask @Inject constructor(
|
|||
null,
|
||||
it
|
||||
)
|
||||
} ?: kotlin.run {
|
||||
} ?: run {
|
||||
ssssService.generateKey(
|
||||
UUID.randomUUID().toString(),
|
||||
params.keySpec,
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package im.vector.app.features.crypto.recover
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.text.InputType.TYPE_CLASS_TEXT
|
||||
import android.text.InputType.TYPE_TEXT_FLAG_MULTI_LINE
|
||||
|
@ -32,6 +31,7 @@ import com.jakewharton.rxbinding3.widget.editorActionEvents
|
|||
import com.jakewharton.rxbinding3.widget.textChanges
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.hideKeyboard
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.extensions.showPassword
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.resources.ColorProvider
|
||||
|
@ -82,7 +82,7 @@ class BootstrapMigrateBackupFragment @Inject constructor(
|
|||
bootstrapMigrateContinueButton.debouncedClicks { submit() }
|
||||
bootstrapMigrateShowPassword.debouncedClicks { sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility) }
|
||||
bootstrapMigrateForgotPassphrase.debouncedClicks { sharedViewModel.handle(BootstrapActions.HandleForgotBackupPassphrase) }
|
||||
bootstrapMigrateUseFile.debouncedClicks { startImportTextFromFileIntent(this, IMPORT_FILE_REQ) }
|
||||
bootstrapMigrateUseFile.debouncedClicks { startImportTextFromFileIntent(requireContext(), importFileStartForActivityResult) }
|
||||
}
|
||||
|
||||
private fun submit() = withState(sharedViewModel) { state ->
|
||||
|
@ -147,9 +147,9 @@ class BootstrapMigrateBackupFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == IMPORT_FILE_REQ && resultCode == Activity.RESULT_OK) {
|
||||
data?.data?.let { dataURI ->
|
||||
private val importFileStartForActivityResult = registerStartForActivityResult { activityResult ->
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
activityResult.data?.data?.let { dataURI ->
|
||||
tryOrNull {
|
||||
activity?.contentResolver?.openInputStream(dataURI)
|
||||
?.bufferedReader()
|
||||
|
@ -159,12 +159,6 @@ class BootstrapMigrateBackupFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val IMPORT_FILE_REQ = 0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
package im.vector.app.features.crypto.recover
|
||||
|
||||
import android.app.Activity.RESULT_OK
|
||||
import android.app.Activity
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
|
@ -25,6 +25,7 @@ import androidx.core.view.isVisible
|
|||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.resources.ColorProvider
|
||||
import im.vector.app.core.utils.startSharePlainTextIntent
|
||||
|
@ -65,43 +66,46 @@ class BootstrapSaveRecoveryKeyFragment @Inject constructor(
|
|||
|
||||
try {
|
||||
sharedViewModel.handle(BootstrapActions.SaveReqQueryStarted)
|
||||
startActivityForResult(Intent.createChooser(intent, getString(R.string.keys_backup_setup_step3_please_make_copy)), REQUEST_CODE_SAVE)
|
||||
saveStartForActivityResult.launch(Intent.createChooser(intent, getString(R.string.keys_backup_setup_step3_please_make_copy)))
|
||||
} catch (activityNotFoundException: ActivityNotFoundException) {
|
||||
requireActivity().toast(R.string.error_no_external_application_found)
|
||||
sharedViewModel.handle(BootstrapActions.SaveReqFailed)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == REQUEST_CODE_SAVE) {
|
||||
val uri = data?.data
|
||||
if (resultCode == RESULT_OK && uri != null) {
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
sharedViewModel.handle(BootstrapActions.SaveKeyToUri(requireContext().contentResolver!!.openOutputStream(uri)!!))
|
||||
} catch (failure: Throwable) {
|
||||
sharedViewModel.handle(BootstrapActions.SaveReqFailed)
|
||||
}
|
||||
private val saveStartForActivityResult = registerStartForActivityResult { activityResult ->
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
val uri = activityResult.data?.data ?: return@registerStartForActivityResult
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
sharedViewModel.handle(BootstrapActions.SaveKeyToUri(requireContext().contentResolver!!.openOutputStream(uri)!!))
|
||||
} catch (failure: Throwable) {
|
||||
sharedViewModel.handle(BootstrapActions.SaveReqFailed)
|
||||
}
|
||||
} else {
|
||||
// result code seems to be always cancelled here.. so act as if it was saved
|
||||
sharedViewModel.handle(BootstrapActions.SaveReqFailed)
|
||||
}
|
||||
return
|
||||
} else if (requestCode == REQUEST_CODE_COPY) {
|
||||
} else {
|
||||
// result code seems to be always cancelled here.. so act as if it was saved
|
||||
sharedViewModel.handle(BootstrapActions.SaveReqFailed)
|
||||
}
|
||||
}
|
||||
|
||||
private val copyStartForActivityResult = registerStartForActivityResult { activityResult ->
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
sharedViewModel.handle(BootstrapActions.RecoveryKeySaved)
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
private fun shareRecoveryKey() = withState(sharedViewModel) { state ->
|
||||
val recoveryKey = state.recoveryKeyCreationInfo?.recoveryKey?.formatRecoveryKey()
|
||||
?: return@withState
|
||||
|
||||
startSharePlainTextIntent(this,
|
||||
startSharePlainTextIntent(
|
||||
this,
|
||||
copyStartForActivityResult,
|
||||
context?.getString(R.string.keys_backup_setup_step3_share_intent_chooser_title),
|
||||
recoveryKey,
|
||||
context?.getString(R.string.recovery_key), REQUEST_CODE_COPY)
|
||||
context?.getString(R.string.recovery_key)
|
||||
)
|
||||
}
|
||||
|
||||
override fun invalidate() = withState(sharedViewModel) { state ->
|
||||
|
@ -111,9 +115,4 @@ class BootstrapSaveRecoveryKeyFragment @Inject constructor(
|
|||
recoveryContinue.isVisible = step.isSaved
|
||||
bootstrapRecoveryKeyText.text = state.recoveryKeyCreationInfo?.recoveryKey?.formatRecoveryKey()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val REQUEST_CODE_SAVE = 123
|
||||
const val REQUEST_CODE_COPY = 124
|
||||
}
|
||||
}
|
||||
|
|
|
@ -301,7 +301,7 @@ class BootstrapSharedViewModel @AssistedInject constructor(
|
|||
// =======================================
|
||||
private fun saveRecoveryKeyToUri(os: OutputStream) = withState { state ->
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
kotlin.runCatching {
|
||||
runCatching {
|
||||
os.use {
|
||||
os.write((state.recoveryKeyCreationInfo?.recoveryKey?.formatRecoveryKey() ?: "").toByteArray())
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ package im.vector.app.features.crypto.verification
|
|||
|
||||
import android.app.Activity
|
||||
import android.app.Dialog
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.KeyEvent
|
||||
|
@ -35,6 +34,7 @@ import im.vector.app.R
|
|||
import im.vector.app.core.di.ScreenComponent
|
||||
import im.vector.app.core.extensions.commitTransaction
|
||||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
||||
import im.vector.app.features.crypto.quads.SharedSecureStorageActivity
|
||||
|
@ -108,12 +108,12 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||
when (it) {
|
||||
is VerificationBottomSheetViewEvents.Dismiss -> dismiss()
|
||||
is VerificationBottomSheetViewEvents.AccessSecretStore -> {
|
||||
startActivityForResult(SharedSecureStorageActivity.newIntent(
|
||||
secretStartForActivityResult.launch(SharedSecureStorageActivity.newIntent(
|
||||
requireContext(),
|
||||
null, // use default key
|
||||
listOf(MASTER_KEY_SSSS_NAME, USER_SIGNING_KEY_SSSS_NAME, SELF_SIGNING_KEY_SSSS_NAME, KEYBACKUP_SECRET_SSSS_NAME),
|
||||
SharedSecureStorageActivity.DEFAULT_RESULT_KEYSTORE_ALIAS
|
||||
), SECRET_REQUEST_CODE)
|
||||
))
|
||||
}
|
||||
is VerificationBottomSheetViewEvents.ModalError -> {
|
||||
AlertDialog.Builder(requireContext())
|
||||
|
@ -145,10 +145,10 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (resultCode == Activity.RESULT_OK && requestCode == SECRET_REQUEST_CODE) {
|
||||
val result = data?.getStringExtra(SharedSecureStorageActivity.EXTRA_DATA_RESULT)
|
||||
val reset = data?.getBooleanExtra(SharedSecureStorageActivity.EXTRA_DATA_RESET, false) ?: false
|
||||
private val secretStartForActivityResult = registerStartForActivityResult { activityResult ->
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
val result = activityResult.data?.getStringExtra(SharedSecureStorageActivity.EXTRA_DATA_RESULT)
|
||||
val reset = activityResult.data?.getBooleanExtra(SharedSecureStorageActivity.EXTRA_DATA_RESET, false) ?: false
|
||||
if (result != null) {
|
||||
viewModel.handle(VerificationAction.GotResultFromSsss(result, SharedSecureStorageActivity.DEFAULT_RESULT_KEYSTORE_ALIAS))
|
||||
} else if (reset) {
|
||||
|
@ -156,11 +156,9 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||
viewModel.handle(VerificationAction.SecuredStorageHasBeenReset)
|
||||
}
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
override fun invalidate() = withState(viewModel) { state ->
|
||||
|
||||
state.otherUserMxItem?.let { matrixItem ->
|
||||
if (state.isMe) {
|
||||
avatarRenderer.render(matrixItem, otherUserAvatarImageView)
|
||||
|
@ -347,9 +345,6 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val SECRET_REQUEST_CODE = 101
|
||||
|
||||
fun withArgs(roomId: String?, otherUserId: String, transactionId: String? = null): VerificationBottomSheet {
|
||||
return VerificationBottomSheet().apply {
|
||||
arguments = Bundle().apply {
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
package im.vector.app.features.crypto.verification.choose
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
|
@ -25,11 +24,11 @@ import com.airbnb.mvrx.withState
|
|||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
||||
import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA
|
||||
import im.vector.app.core.utils.allGranted
|
||||
import im.vector.app.core.utils.checkPermissions
|
||||
import im.vector.app.core.utils.registerForPermissionsResult
|
||||
import im.vector.app.features.crypto.verification.VerificationAction
|
||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
||||
import im.vector.app.features.qrcode.QrCodeScannerActivity
|
||||
|
@ -75,16 +74,14 @@ class VerificationChooseMethodFragment @Inject constructor(
|
|||
state.pendingRequest.invoke()?.transactionId ?: ""))
|
||||
}
|
||||
|
||||
override fun openCamera() {
|
||||
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this, PERMISSION_REQUEST_CODE_LAUNCH_CAMERA)) {
|
||||
private val openCameraActivityResultLauncher = registerForPermissionsResult { allGranted ->
|
||||
if (allGranted) {
|
||||
doOpenQRCodeScanner()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
|
||||
if (requestCode == PERMISSION_REQUEST_CODE_LAUNCH_CAMERA && allGranted(grantResults)) {
|
||||
override fun openCamera() {
|
||||
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), openCameraActivityResultLauncher)) {
|
||||
doOpenQRCodeScanner()
|
||||
}
|
||||
}
|
||||
|
@ -94,24 +91,18 @@ class VerificationChooseMethodFragment @Inject constructor(
|
|||
}
|
||||
|
||||
private fun doOpenQRCodeScanner() {
|
||||
QrCodeScannerActivity.startForResult(this)
|
||||
QrCodeScannerActivity.startForResult(requireActivity(), scanActivityResultLauncher)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
private val scanActivityResultLauncher = registerStartForActivityResult { activityResult ->
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
val scannedQrCode = QrCodeScannerActivity.getResultText(activityResult.data)
|
||||
val wasQrCode = QrCodeScannerActivity.getResultIsQrCode(activityResult.data)
|
||||
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
when (requestCode) {
|
||||
QrCodeScannerActivity.QR_CODE_SCANNER_REQUEST_CODE -> {
|
||||
val scannedQrCode = QrCodeScannerActivity.getResultText(data)
|
||||
val wasQrCode = QrCodeScannerActivity.getResultIsQrCode(data)
|
||||
|
||||
if (wasQrCode && !scannedQrCode.isNullOrBlank()) {
|
||||
onRemoteQrCodeScanned(scannedQrCode)
|
||||
} else {
|
||||
Timber.w("It was not a QR code, or empty result")
|
||||
}
|
||||
}
|
||||
if (wasQrCode && !scannedQrCode.isNullOrBlank()) {
|
||||
onRemoteQrCodeScanned(scannedQrCode)
|
||||
} else {
|
||||
Timber.w("It was not a QR code, or empty result")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ abstract class BottomSheetVerificationEmojisItem : VectorEpoxyModel<BottomSheetV
|
|||
view.findViewById<TextView>(R.id.item_emoji_tv).isVisible = false
|
||||
view.findViewById<ImageView>(R.id.item_emoji_image).isVisible = true
|
||||
view.findViewById<ImageView>(R.id.item_emoji_image).setImageDrawable(ContextCompat.getDrawable(view.context, it))
|
||||
} ?: kotlin.run {
|
||||
} ?: run {
|
||||
view.findViewById<TextView>(R.id.item_emoji_tv).isVisible = true
|
||||
view.findViewById<ImageView>(R.id.item_emoji_image).isVisible = false
|
||||
view.findViewById<TextView>(R.id.item_emoji_tv).text = rep.emoji
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
package im.vector.app.features.discovery
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
|
@ -27,12 +26,12 @@ import im.vector.app.core.extensions.cleanup
|
|||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.extensions.observeEvent
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.utils.ensureProtocol
|
||||
import im.vector.app.features.discovery.change.SetIdentityServerFragment
|
||||
import im.vector.app.features.settings.VectorSettingsActivity
|
||||
import im.vector.app.features.terms.ReviewTermsActivity
|
||||
import org.matrix.android.sdk.api.session.identity.SharedState
|
||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||
import org.matrix.android.sdk.api.session.terms.TermsService
|
||||
|
@ -92,22 +91,19 @@ class DiscoverySettingsFragment @Inject constructor(
|
|||
viewModel.handle(DiscoverySettingsAction.Refresh)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == ReviewTermsActivity.TERMS_REQUEST_CODE) {
|
||||
if (Activity.RESULT_OK == resultCode) {
|
||||
viewModel.handle(DiscoverySettingsAction.RetrieveBinding)
|
||||
} else {
|
||||
// add some error?
|
||||
}
|
||||
private val termsActivityResultLauncher = registerStartForActivityResult {
|
||||
if (it.resultCode == Activity.RESULT_OK) {
|
||||
viewModel.handle(DiscoverySettingsAction.RetrieveBinding)
|
||||
} else {
|
||||
// add some error?
|
||||
}
|
||||
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
override fun openIdentityServerTerms() = withState(viewModel) { state ->
|
||||
if (state.termsNotSigned) {
|
||||
navigator.openTerms(
|
||||
this,
|
||||
requireContext(),
|
||||
termsActivityResultLauncher,
|
||||
TermsService.ServiceType.IdentityService,
|
||||
state.identityServer()?.ensureProtocol() ?: "",
|
||||
null)
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
package im.vector.app.features.discovery.change
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.inputmethod.EditorInfo
|
||||
|
@ -28,13 +27,13 @@ import com.airbnb.mvrx.withState
|
|||
import com.jakewharton.rxbinding3.widget.textChanges
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.extensions.toReducedUrl
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.resources.ColorProvider
|
||||
import im.vector.app.core.utils.colorizeMatchingText
|
||||
import im.vector.app.features.discovery.DiscoverySharedViewModel
|
||||
import im.vector.app.features.terms.ReviewTermsActivity
|
||||
import org.matrix.android.sdk.api.session.terms.TermsService
|
||||
import kotlinx.android.synthetic.main.fragment_set_identity_server.*
|
||||
import javax.inject.Inject
|
||||
|
@ -121,7 +120,8 @@ class SetIdentityServerFragment @Inject constructor(
|
|||
is SetIdentityServerViewEvents.TermsAccepted -> processIdentityServerChange()
|
||||
is SetIdentityServerViewEvents.ShowTerms -> {
|
||||
navigator.openTerms(
|
||||
this,
|
||||
requireContext(),
|
||||
termsActivityResultLauncher,
|
||||
TermsService.ServiceType.IdentityService,
|
||||
it.identityServerUrl,
|
||||
null)
|
||||
|
@ -150,15 +150,12 @@ class SetIdentityServerFragment @Inject constructor(
|
|||
(activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.identity_server)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == ReviewTermsActivity.TERMS_REQUEST_CODE) {
|
||||
if (Activity.RESULT_OK == resultCode) {
|
||||
processIdentityServerChange()
|
||||
} else {
|
||||
// add some error?
|
||||
}
|
||||
private val termsActivityResultLauncher = registerStartForActivityResult {
|
||||
if (it.resultCode == Activity.RESULT_OK) {
|
||||
processIdentityServerChange()
|
||||
} else {
|
||||
// add some error?
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
private fun processIdentityServerChange() {
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
package im.vector.app.features.home.room.detail
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity.RESULT_OK
|
||||
import android.app.Activity
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.graphics.Typeface
|
||||
|
@ -73,6 +73,7 @@ import im.vector.app.core.epoxy.LayoutManagerStateRestorer
|
|||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.extensions.hideKeyboard
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.extensions.setTextOrHide
|
||||
import im.vector.app.core.extensions.showKeyboard
|
||||
import im.vector.app.core.extensions.trackItemsVisibilityChange
|
||||
|
@ -91,19 +92,15 @@ import im.vector.app.core.utils.KeyboardStateUtils
|
|||
import im.vector.app.core.utils.PERMISSIONS_FOR_AUDIO_IP_CALL
|
||||
import im.vector.app.core.utils.PERMISSIONS_FOR_VIDEO_IP_CALL
|
||||
import im.vector.app.core.utils.PERMISSIONS_FOR_WRITING_FILES
|
||||
import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_INCOMING_URI
|
||||
import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_PICK_ATTACHMENT
|
||||
import im.vector.app.core.utils.TextUtils
|
||||
import im.vector.app.core.utils.allGranted
|
||||
import im.vector.app.core.utils.checkPermissions
|
||||
import im.vector.app.core.utils.colorizeMatchingText
|
||||
import im.vector.app.core.utils.copyToClipboard
|
||||
import im.vector.app.core.utils.createJSonViewerStyleProvider
|
||||
import im.vector.app.core.utils.createUIHandler
|
||||
import im.vector.app.core.utils.isValidUrl
|
||||
import im.vector.app.core.utils.onPermissionResultAudioIpCall
|
||||
import im.vector.app.core.utils.onPermissionResultVideoIpCall
|
||||
import im.vector.app.core.utils.openUrlInExternalBrowser
|
||||
import im.vector.app.core.utils.registerForPermissionsResult
|
||||
import im.vector.app.core.utils.saveMedia
|
||||
import im.vector.app.core.utils.shareMedia
|
||||
import im.vector.app.core.utils.toast
|
||||
|
@ -138,7 +135,6 @@ import im.vector.app.features.home.room.detail.timeline.item.MessageTextItem
|
|||
import im.vector.app.features.home.room.detail.timeline.item.ReadReceiptData
|
||||
import im.vector.app.features.home.room.detail.timeline.reactions.ViewReactionsBottomSheet
|
||||
import im.vector.app.features.home.room.detail.widget.RoomWidgetsBottomSheet
|
||||
import im.vector.app.features.home.room.detail.widget.WidgetRequestCodes
|
||||
import im.vector.app.features.html.EventHtmlRenderer
|
||||
import im.vector.app.features.html.PillImageSpan
|
||||
import im.vector.app.features.invite.VectorInviteView
|
||||
|
@ -206,8 +202,6 @@ data class RoomDetailArgs(
|
|||
val sharedData: SharedData? = null
|
||||
) : Parcelable
|
||||
|
||||
private const val REACTION_SELECT_REQUEST_CODE = 0
|
||||
|
||||
class RoomDetailFragment @Inject constructor(
|
||||
private val session: Session,
|
||||
private val avatarRenderer: AvatarRenderer,
|
||||
|
@ -234,11 +228,6 @@ class RoomDetailFragment @Inject constructor(
|
|||
ActiveCallView.Callback {
|
||||
|
||||
companion object {
|
||||
|
||||
private const val AUDIO_CALL_PERMISSION_REQUEST_CODE = 1
|
||||
private const val VIDEO_CALL_PERMISSION_REQUEST_CODE = 2
|
||||
private const val SAVE_ATTACHEMENT_REQUEST_CODE = 3
|
||||
|
||||
/**
|
||||
* Sanitize the display name.
|
||||
*
|
||||
|
@ -371,6 +360,10 @@ class RoomDetailFragment @Inject constructor(
|
|||
is RoomDetailViewEvents.RequestNativeWidgetPermission -> requestNativeWidgetPermission(it)
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
handleShareData()
|
||||
}
|
||||
}
|
||||
|
||||
private fun requestNativeWidgetPermission(it: RoomDetailViewEvents.RequestNativeWidgetPermission) {
|
||||
|
@ -401,9 +394,14 @@ class RoomDetailFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private val integrationManagerActivityResultLauncher = registerStartForActivityResult {
|
||||
// Noop
|
||||
}
|
||||
|
||||
private fun openIntegrationManager(screen: String? = null) {
|
||||
navigator.openIntegrationManager(
|
||||
fragment = this,
|
||||
context = requireContext(),
|
||||
activityResultLauncher = integrationManagerActivityResultLauncher,
|
||||
roomId = roomDetailArgs.roomId,
|
||||
integId = null,
|
||||
screen = screen
|
||||
|
@ -440,7 +438,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
}
|
||||
|
||||
private fun openStickerPicker(event: RoomDetailViewEvents.OpenStickerPicker) {
|
||||
navigator.openStickerPicker(this, roomDetailArgs.roomId, event.widget)
|
||||
navigator.openStickerPicker(requireContext(), stickerActivityResultLauncher, roomDetailArgs.roomId, event.widget)
|
||||
}
|
||||
|
||||
private fun startOpenFileIntent(action: RoomDetailViewEvents.OpenFile) {
|
||||
|
@ -480,20 +478,17 @@ class RoomDetailFragment @Inject constructor(
|
|||
navigator.openRoom(vectorBaseActivity, action.roomId)
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
if (savedInstanceState == null) {
|
||||
when (val sharedData = roomDetailArgs.sharedData) {
|
||||
is SharedData.Text -> {
|
||||
roomDetailViewModel.handle(RoomDetailAction.EnterRegularMode(sharedData.text, fromSharing = true))
|
||||
}
|
||||
is SharedData.Attachments -> {
|
||||
// open share edition
|
||||
onContentAttachmentsReady(sharedData.attachmentData)
|
||||
}
|
||||
null -> Timber.v("No share data to process")
|
||||
}.exhaustive
|
||||
}
|
||||
private fun handleShareData() {
|
||||
when (val sharedData = roomDetailArgs.sharedData) {
|
||||
is SharedData.Text -> {
|
||||
roomDetailViewModel.handle(RoomDetailAction.EnterRegularMode(sharedData.text, fromSharing = true))
|
||||
}
|
||||
is SharedData.Attachments -> {
|
||||
// open share edition
|
||||
onContentAttachmentsReady(sharedData.attachmentData)
|
||||
}
|
||||
null -> Timber.v("No share data to process")
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
@ -791,19 +786,33 @@ class RoomDetailFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private val startCallActivityResultLauncher = registerForPermissionsResult { allGranted ->
|
||||
if (allGranted) {
|
||||
(roomDetailViewModel.pendingAction as? RoomDetailAction.StartCall)?.let {
|
||||
roomDetailViewModel.pendingAction = null
|
||||
roomDetailViewModel.handle(it)
|
||||
}
|
||||
} else {
|
||||
context?.toast(R.string.permissions_action_not_performed_missing_permissions)
|
||||
cleanUpAfterPermissionNotGranted()
|
||||
}
|
||||
}
|
||||
|
||||
private fun safeStartCall2(isVideoCall: Boolean) {
|
||||
val startCallAction = RoomDetailAction.StartCall(isVideoCall)
|
||||
roomDetailViewModel.pendingAction = startCallAction
|
||||
if (isVideoCall) {
|
||||
if (checkPermissions(PERMISSIONS_FOR_VIDEO_IP_CALL,
|
||||
this, VIDEO_CALL_PERMISSION_REQUEST_CODE,
|
||||
requireActivity(),
|
||||
startCallActivityResultLauncher,
|
||||
R.string.permissions_rationale_msg_camera_and_audio)) {
|
||||
roomDetailViewModel.pendingAction = null
|
||||
roomDetailViewModel.handle(startCallAction)
|
||||
}
|
||||
} else {
|
||||
if (checkPermissions(PERMISSIONS_FOR_AUDIO_IP_CALL,
|
||||
this, AUDIO_CALL_PERMISSION_REQUEST_CODE,
|
||||
requireActivity(),
|
||||
startCallActivityResultLauncher,
|
||||
R.string.permissions_rationale_msg_record_audio)) {
|
||||
roomDetailViewModel.pendingAction = null
|
||||
roomDetailViewModel.handle(startCallAction)
|
||||
|
@ -879,27 +888,63 @@ class RoomDetailFragment @Inject constructor(
|
|||
roomDetailViewModel.handle(RoomDetailAction.SaveDraft(composerLayout.composerEditText.text.toString()))
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
val hasBeenHandled = attachmentsHelper.onActivityResult(requestCode, resultCode, data)
|
||||
if (!hasBeenHandled && resultCode == RESULT_OK && data != null) {
|
||||
when (requestCode) {
|
||||
AttachmentsPreviewActivity.REQUEST_CODE -> {
|
||||
val sendData = AttachmentsPreviewActivity.getOutput(data)
|
||||
val keepOriginalSize = AttachmentsPreviewActivity.getKeepOriginalSize(data)
|
||||
roomDetailViewModel.handle(RoomDetailAction.SendMedia(sendData, !keepOriginalSize))
|
||||
}
|
||||
REACTION_SELECT_REQUEST_CODE -> {
|
||||
val (eventId, reaction) = EmojiReactionPickerActivity.getOutput(data) ?: return
|
||||
roomDetailViewModel.handle(RoomDetailAction.SendReaction(eventId, reaction))
|
||||
}
|
||||
WidgetRequestCodes.STICKER_PICKER_REQUEST_CODE -> {
|
||||
val content = WidgetActivity.getOutput(data).toModel<MessageStickerContent>() ?: return
|
||||
roomDetailViewModel.handle(RoomDetailAction.SendSticker(content))
|
||||
}
|
||||
private val attachmentFileActivityResultLauncher = registerStartForActivityResult {
|
||||
if (it.resultCode == Activity.RESULT_OK) {
|
||||
attachmentsHelper.onImageResult(it.data)
|
||||
}
|
||||
}
|
||||
|
||||
private val attachmentAudioActivityResultLauncher = registerStartForActivityResult {
|
||||
if (it.resultCode == Activity.RESULT_OK) {
|
||||
attachmentsHelper.onAudioResult(it.data)
|
||||
}
|
||||
}
|
||||
|
||||
private val attachmentContactActivityResultLauncher = registerStartForActivityResult {
|
||||
if (it.resultCode == Activity.RESULT_OK) {
|
||||
attachmentsHelper.onContactResult(it.data)
|
||||
}
|
||||
}
|
||||
|
||||
private val attachmentImageActivityResultLauncher = registerStartForActivityResult {
|
||||
if (it.resultCode == Activity.RESULT_OK) {
|
||||
attachmentsHelper.onImageResult(it.data)
|
||||
}
|
||||
}
|
||||
|
||||
private val attachmentPhotoActivityResultLauncher = registerStartForActivityResult {
|
||||
if (it.resultCode == Activity.RESULT_OK) {
|
||||
attachmentsHelper.onPhotoResult()
|
||||
}
|
||||
}
|
||||
|
||||
private val contentAttachmentActivityResultLauncher = registerStartForActivityResult { activityResult ->
|
||||
val data = activityResult.data ?: return@registerStartForActivityResult
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
val sendData = AttachmentsPreviewActivity.getOutput(data)
|
||||
val keepOriginalSize = AttachmentsPreviewActivity.getKeepOriginalSize(data)
|
||||
roomDetailViewModel.handle(RoomDetailAction.SendMedia(sendData, !keepOriginalSize))
|
||||
}
|
||||
}
|
||||
|
||||
private val emojiActivityResultLauncher = registerStartForActivityResult { activityResult ->
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
val eventId = EmojiReactionPickerActivity.getOutputEventId(activityResult.data)
|
||||
val reaction = EmojiReactionPickerActivity.getOutputReaction(activityResult.data)
|
||||
if (eventId != null && reaction != null) {
|
||||
roomDetailViewModel.handle(RoomDetailAction.SendReaction(eventId, reaction))
|
||||
}
|
||||
}
|
||||
// TODO why don't we call super here?
|
||||
// super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
private val stickerActivityResultLauncher = registerStartForActivityResult { activityResult ->
|
||||
val data = activityResult.data ?: return@registerStartForActivityResult
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
WidgetActivity.getOutput(data).toModel<MessageStickerContent>()
|
||||
?.let { content ->
|
||||
roomDetailViewModel.handle(RoomDetailAction.SendSticker(content))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PRIVATE METHODS *****************************************************************************
|
||||
|
@ -994,6 +1039,18 @@ class RoomDetailFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private val writingFileActivityResultLauncher = registerForPermissionsResult { allGranted ->
|
||||
if (allGranted) {
|
||||
val pendingUri = roomDetailViewModel.pendingUri
|
||||
if (pendingUri != null) {
|
||||
roomDetailViewModel.pendingUri = null
|
||||
sendUri(pendingUri)
|
||||
}
|
||||
} else {
|
||||
cleanUpAfterPermissionNotGranted()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupComposer() {
|
||||
autoCompleter.setup(composerLayout.composerEditText)
|
||||
|
||||
|
@ -1026,7 +1083,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
|
||||
override fun onRichContentSelected(contentUri: Uri): Boolean {
|
||||
// We need WRITE_EXTERNAL permission
|
||||
return if (checkPermissions(PERMISSIONS_FOR_WRITING_FILES, this@RoomDetailFragment, PERMISSION_REQUEST_CODE_INCOMING_URI)) {
|
||||
return if (checkPermissions(PERMISSIONS_FOR_WRITING_FILES, requireActivity(), writingFileActivityResultLauncher)) {
|
||||
sendUri(contentUri)
|
||||
} else {
|
||||
roomDetailViewModel.pendingUri = contentUri
|
||||
|
@ -1416,52 +1473,11 @@ class RoomDetailFragment @Inject constructor(
|
|||
// // }
|
||||
// }
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||
if (allGranted(grantResults)) {
|
||||
when (requestCode) {
|
||||
SAVE_ATTACHEMENT_REQUEST_CODE -> {
|
||||
sharedActionViewModel.pendingAction?.let {
|
||||
handleActions(it)
|
||||
sharedActionViewModel.pendingAction = null
|
||||
}
|
||||
}
|
||||
PERMISSION_REQUEST_CODE_INCOMING_URI -> {
|
||||
val pendingUri = roomDetailViewModel.pendingUri
|
||||
if (pendingUri != null) {
|
||||
roomDetailViewModel.pendingUri = null
|
||||
sendUri(pendingUri)
|
||||
}
|
||||
}
|
||||
PERMISSION_REQUEST_CODE_PICK_ATTACHMENT -> {
|
||||
val pendingType = attachmentsHelper.pendingType
|
||||
if (pendingType != null) {
|
||||
attachmentsHelper.pendingType = null
|
||||
launchAttachmentProcess(pendingType)
|
||||
}
|
||||
}
|
||||
AUDIO_CALL_PERMISSION_REQUEST_CODE -> {
|
||||
if (onPermissionResultAudioIpCall(requireContext(), grantResults)) {
|
||||
(roomDetailViewModel.pendingAction as? RoomDetailAction.StartCall)?.let {
|
||||
roomDetailViewModel.pendingAction = null
|
||||
roomDetailViewModel.handle(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
VIDEO_CALL_PERMISSION_REQUEST_CODE -> {
|
||||
if (onPermissionResultVideoIpCall(requireContext(), grantResults)) {
|
||||
(roomDetailViewModel.pendingAction as? RoomDetailAction.StartCall)?.let {
|
||||
roomDetailViewModel.pendingAction = null
|
||||
roomDetailViewModel.handle(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Reset all pending data
|
||||
roomDetailViewModel.pendingAction = null
|
||||
roomDetailViewModel.pendingUri = null
|
||||
attachmentsHelper.pendingType = null
|
||||
}
|
||||
private fun cleanUpAfterPermissionNotGranted() {
|
||||
// Reset all pending data
|
||||
roomDetailViewModel.pendingAction = null
|
||||
roomDetailViewModel.pendingUri = null
|
||||
attachmentsHelper.pendingType = null
|
||||
}
|
||||
|
||||
// override fun onAudioMessageClicked(messageAudioContent: MessageAudioContent) {
|
||||
|
@ -1576,9 +1592,20 @@ class RoomDetailFragment @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private val saveActionActivityResultLauncher = registerForPermissionsResult { allGranted ->
|
||||
if (allGranted) {
|
||||
sharedActionViewModel.pendingAction?.let {
|
||||
handleActions(it)
|
||||
sharedActionViewModel.pendingAction = null
|
||||
}
|
||||
} else {
|
||||
cleanUpAfterPermissionNotGranted()
|
||||
}
|
||||
}
|
||||
|
||||
private fun onSaveActionClicked(action: EventSharedAction.Save) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q
|
||||
&& !checkPermissions(PERMISSIONS_FOR_WRITING_FILES, this, SAVE_ATTACHEMENT_REQUEST_CODE)) {
|
||||
&& !checkPermissions(PERMISSIONS_FOR_WRITING_FILES, requireActivity(), saveActionActivityResultLauncher)) {
|
||||
sharedActionViewModel.pendingAction = action
|
||||
return
|
||||
}
|
||||
|
@ -1611,7 +1638,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
openRoomMemberProfile(action.userId)
|
||||
}
|
||||
is EventSharedAction.AddReaction -> {
|
||||
startActivityForResult(EmojiReactionPickerActivity.intent(requireContext(), action.eventId), REACTION_SELECT_REQUEST_CODE)
|
||||
emojiActivityResultLauncher.launch(EmojiReactionPickerActivity.intent(requireContext(), action.eventId))
|
||||
}
|
||||
is EventSharedAction.ViewReactions -> {
|
||||
ViewReactionsBottomSheet.newInstance(roomDetailArgs.roomId, action.messageInformationData)
|
||||
|
@ -1816,8 +1843,20 @@ class RoomDetailFragment @Inject constructor(
|
|||
|
||||
// AttachmentTypeSelectorView.Callback
|
||||
|
||||
private val typeSelectedActivityResultLauncher = registerForPermissionsResult { allGranted ->
|
||||
if (allGranted) {
|
||||
val pendingType = attachmentsHelper.pendingType
|
||||
if (pendingType != null) {
|
||||
attachmentsHelper.pendingType = null
|
||||
launchAttachmentProcess(pendingType)
|
||||
}
|
||||
} else {
|
||||
cleanUpAfterPermissionNotGranted()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTypeSelected(type: AttachmentTypeSelectorView.Type) {
|
||||
if (checkPermissions(type.permissionsBit, this, PERMISSION_REQUEST_CODE_PICK_ATTACHMENT)) {
|
||||
if (checkPermissions(type.permissionsBit, requireActivity(), typeSelectedActivityResultLauncher)) {
|
||||
launchAttachmentProcess(type)
|
||||
} else {
|
||||
attachmentsHelper.pendingType = type
|
||||
|
@ -1826,11 +1865,11 @@ class RoomDetailFragment @Inject constructor(
|
|||
|
||||
private fun launchAttachmentProcess(type: AttachmentTypeSelectorView.Type) {
|
||||
when (type) {
|
||||
AttachmentTypeSelectorView.Type.CAMERA -> attachmentsHelper.openCamera(this)
|
||||
AttachmentTypeSelectorView.Type.FILE -> attachmentsHelper.selectFile(this)
|
||||
AttachmentTypeSelectorView.Type.GALLERY -> attachmentsHelper.selectGallery(this)
|
||||
AttachmentTypeSelectorView.Type.AUDIO -> attachmentsHelper.selectAudio(this)
|
||||
AttachmentTypeSelectorView.Type.CONTACT -> attachmentsHelper.selectContact(this)
|
||||
AttachmentTypeSelectorView.Type.CAMERA -> attachmentsHelper.openCamera(requireContext(), attachmentPhotoActivityResultLauncher)
|
||||
AttachmentTypeSelectorView.Type.FILE -> attachmentsHelper.selectFile(attachmentFileActivityResultLauncher)
|
||||
AttachmentTypeSelectorView.Type.GALLERY -> attachmentsHelper.selectGallery(attachmentImageActivityResultLauncher)
|
||||
AttachmentTypeSelectorView.Type.AUDIO -> attachmentsHelper.selectAudio(attachmentAudioActivityResultLauncher)
|
||||
AttachmentTypeSelectorView.Type.CONTACT -> attachmentsHelper.selectContact(attachmentContactActivityResultLauncher)
|
||||
AttachmentTypeSelectorView.Type.STICKER -> roomDetailViewModel.handle(RoomDetailAction.SelectStickerAttachment)
|
||||
}.exhaustive
|
||||
}
|
||||
|
@ -1849,7 +1888,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
}
|
||||
if (grouped.previewables.isNotEmpty()) {
|
||||
val intent = AttachmentsPreviewActivity.newIntent(requireContext(), AttachmentsPreviewArgs(grouped.previewables))
|
||||
startActivityForResult(intent, AttachmentsPreviewActivity.REQUEST_CODE)
|
||||
contentAttachmentActivityResultLauncher.launch(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1074,7 +1074,7 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||
.buffer(1, TimeUnit.SECONDS)
|
||||
.filter { it.isNotEmpty() }
|
||||
.subscribeBy(onNext = { actions ->
|
||||
val bufferedMostRecentDisplayedEvent = actions.maxBy { it.event.displayIndex }?.event ?: return@subscribeBy
|
||||
val bufferedMostRecentDisplayedEvent = actions.maxByOrNull { it.event.displayIndex }?.event ?: return@subscribeBy
|
||||
val globalMostRecentDisplayedEvent = mostRecentDisplayedEvent
|
||||
if (trackUnreadMessages.get()) {
|
||||
if (globalMostRecentDisplayedEvent == null) {
|
||||
|
|
|
@ -18,6 +18,7 @@ package im.vector.app.features.home.room.detail.readreceipts
|
|||
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import butterknife.BindView
|
||||
import com.airbnb.mvrx.MvRx
|
||||
|
@ -59,8 +60,8 @@ class DisplayReadReceiptsBottomSheet : VectorBaseBottomSheetDialogFragment(), Di
|
|||
|
||||
override fun getLayoutResId() = R.layout.bottom_sheet_generic_list_with_title
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java)
|
||||
recyclerView.configureWith(epoxyController, hasFixedSize = false)
|
||||
bottomSheetTitle.text = getString(R.string.seen_by)
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package im.vector.app.features.home.room.detail.timeline.action
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import butterknife.BindView
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
|
@ -51,8 +52,8 @@ class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), Message
|
|||
|
||||
override fun getLayoutResId() = R.layout.bottom_sheet_generic_list
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java)
|
||||
recyclerView.configureWith(messageActionsEpoxyController, hasFixedSize = false, disableItemAnimation = true)
|
||||
messageActionsEpoxyController.listener = this
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package im.vector.app.features.home.room.detail.timeline.edithistory
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import butterknife.BindView
|
||||
import com.airbnb.mvrx.MvRx
|
||||
|
@ -55,8 +56,8 @@ class ViewEditHistoryBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||
|
||||
override fun getLayoutResId() = R.layout.bottom_sheet_generic_list_with_title
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
recyclerView.configureWith(
|
||||
epoxyController,
|
||||
showDivider = true,
|
||||
|
|
|
@ -84,7 +84,7 @@ abstract class MessagePollItem : AbsMessageItem<MessagePollItem.Holder>() {
|
|||
}
|
||||
} else {
|
||||
holder.resultWrapper.isVisible = true
|
||||
val maxCount = votes?.maxBy { it.value }?.value ?: 0
|
||||
val maxCount = votes?.maxByOrNull { it.value }?.value ?: 0
|
||||
optionsContent?.options?.forEachIndexed { index, item ->
|
||||
if (index < resultLines.size) {
|
||||
val optionCount = votes?.get(index) ?: 0
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package im.vector.app.features.home.room.detail.timeline.reactions
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import butterknife.BindView
|
||||
import com.airbnb.mvrx.MvRx
|
||||
|
@ -55,8 +56,8 @@ class ViewReactionsBottomSheet : VectorBaseBottomSheetDialogFragment(), ViewReac
|
|||
|
||||
override fun getLayoutResId() = R.layout.bottom_sheet_generic_list_with_title
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java)
|
||||
recyclerView.configureWith(epoxyController, hasFixedSize = false, showDivider = true)
|
||||
bottomSheetTitle.text = context?.getString(R.string.reactions)
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package im.vector.app.features.home.room.detail.widget
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import butterknife.BindView
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
|
@ -55,8 +56,8 @@ class RoomWidgetsBottomSheet : VectorBaseBottomSheetDialogFragment(), RoomWidget
|
|||
|
||||
override fun getLayoutResId() = R.layout.bottom_sheet_generic_list_with_title
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
recyclerView.configureWith(epoxyController, hasFixedSize = false)
|
||||
bottomSheetTitle.text = getString(R.string.active_widgets_title)
|
||||
bottomSheetTitle.textSize = 20f
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.home.room.detail.widget
|
||||
|
||||
object WidgetRequestCodes {
|
||||
const val STICKER_PICKER_REQUEST_CODE = 16000
|
||||
const val INTEGRATION_MANAGER_REQUEST_CODE = 16001
|
||||
}
|
|
@ -18,6 +18,7 @@ package im.vector.app.features.home.room.list.actions
|
|||
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import butterknife.BindView
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
|
@ -67,8 +68,8 @@ class RoomListQuickActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), R
|
|||
|
||||
override fun getLayoutResId() = R.layout.bottom_sheet_generic_list
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
sharedActionViewModel = activityViewModelProvider.get(RoomListQuickActionsSharedActionViewModel::class.java)
|
||||
recyclerView.configureWith(roomListActionsEpoxyController, viewPool = sharedViewPool, hasFixedSize = false, disableItemAnimation = true)
|
||||
roomListActionsEpoxyController.listener = this
|
||||
|
|
|
@ -112,6 +112,7 @@ class InviteUsersToRoomActivity : SimpleFragmentActivity() {
|
|||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
if (allGranted(grantResults)) {
|
||||
if (requestCode == PERMISSION_REQUEST_CODE_READ_CONTACTS) {
|
||||
doOnPostResume { addFragmentToBackstack(R.id.container, ContactsBookFragment::class.java) }
|
||||
|
|
|
@ -30,6 +30,7 @@ import com.yalantis.ucrop.UCrop
|
|||
import im.vector.app.R
|
||||
import im.vector.app.core.di.ActiveSessionHolder
|
||||
import im.vector.app.core.di.ScreenComponent
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.core.resources.ColorProvider
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
|
@ -112,10 +113,10 @@ class BigImageViewerActivity : VectorBaseActivity() {
|
|||
private fun onAvatarTypeSelected(isCamera: Boolean) {
|
||||
if (isCamera) {
|
||||
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this, PERMISSION_REQUEST_CODE_LAUNCH_CAMERA)) {
|
||||
avatarCameraUri = MultiPicker.get(MultiPicker.CAMERA).startWithExpectingFile(this)
|
||||
avatarCameraUri = MultiPicker.get(MultiPicker.CAMERA).startWithExpectingFile(this, takePhotoActivityResultLauncher)
|
||||
}
|
||||
} else {
|
||||
MultiPicker.get(MultiPicker.IMAGE).single().startWith(this)
|
||||
MultiPicker.get(MultiPicker.IMAGE).single().startWith(pickImageActivityResultLauncher)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,33 +128,43 @@ class BigImageViewerActivity : VectorBaseActivity() {
|
|||
.start(this)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
when (requestCode) {
|
||||
MultiPicker.REQUEST_CODE_TAKE_PHOTO -> {
|
||||
avatarCameraUri?.let { uri ->
|
||||
MultiPicker.get(MultiPicker.CAMERA)
|
||||
.getTakenPhoto(this, requestCode, resultCode, uri)
|
||||
?.let {
|
||||
onRoomAvatarSelected(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
MultiPicker.REQUEST_CODE_PICK_IMAGE -> {
|
||||
MultiPicker
|
||||
.get(MultiPicker.IMAGE)
|
||||
.getSelectedFiles(this, requestCode, resultCode, data)
|
||||
.firstOrNull()?.let {
|
||||
onRoomAvatarSelected(it)
|
||||
}
|
||||
}
|
||||
UCrop.REQUEST_CROP -> data?.let { onAvatarCropped(UCrop.getOutput(it)) }
|
||||
private val takePhotoActivityResultLauncher = registerStartForActivityResult { activityResult ->
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
avatarCameraUri?.let { uri ->
|
||||
MultiPicker.get(MultiPicker.CAMERA)
|
||||
.getTakenPhoto(this, uri)
|
||||
?.let {
|
||||
onRoomAvatarSelected(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val pickImageActivityResultLauncher = registerStartForActivityResult { activityResult ->
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
MultiPicker
|
||||
.get(MultiPicker.IMAGE)
|
||||
.getSelectedFiles(this, activityResult.data)
|
||||
.firstOrNull()?.let {
|
||||
onRoomAvatarSelected(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
// TODO handle this one (Ucrop lib)
|
||||
@Suppress("DEPRECATION")
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
when (requestCode) {
|
||||
UCrop.REQUEST_CROP -> data?.let { onAvatarCropped(UCrop.getOutput(it)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
if (allGranted(grantResults)) {
|
||||
when (requestCode) {
|
||||
PERMISSION_REQUEST_CODE_LAUNCH_CAMERA -> onAvatarTypeSelected(true)
|
||||
|
@ -174,7 +185,6 @@ class BigImageViewerActivity : VectorBaseActivity() {
|
|||
private const val EXTRA_TITLE = "EXTRA_TITLE"
|
||||
private const val EXTRA_IMAGE_URL = "EXTRA_IMAGE_URL"
|
||||
private const val EXTRA_CAN_EDIT_IMAGE = "EXTRA_CAN_EDIT_IMAGE"
|
||||
const val REQUEST_CODE = 1000
|
||||
|
||||
fun newIntent(context: Context, title: String?, imageUrl: String, canEditImage: Boolean = false): Intent {
|
||||
return Intent(context, BigImageViewerActivity::class.java).apply {
|
||||
|
|
|
@ -21,11 +21,11 @@ import android.content.Context
|
|||
import android.content.Intent
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.core.app.ActivityOptionsCompat
|
||||
import androidx.core.app.TaskStackBuilder
|
||||
import androidx.core.util.Pair
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.di.ActiveSessionHolder
|
||||
import im.vector.app.core.error.fatalError
|
||||
|
@ -45,7 +45,6 @@ import im.vector.app.features.home.room.detail.RoomDetailActivity
|
|||
import im.vector.app.features.home.room.detail.RoomDetailArgs
|
||||
import im.vector.app.features.home.room.detail.search.SearchActivity
|
||||
import im.vector.app.features.home.room.detail.search.SearchArgs
|
||||
import im.vector.app.features.home.room.detail.widget.WidgetRequestCodes
|
||||
import im.vector.app.features.home.room.filtered.FilteredRoomsActivity
|
||||
import im.vector.app.features.invite.InviteUsersToRoomActivity
|
||||
import im.vector.app.features.media.AttachmentData
|
||||
|
@ -266,21 +265,32 @@ class DefaultNavigator @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun openTerms(fragment: Fragment, serviceType: TermsService.ServiceType, baseUrl: String, token: String?, requestCode: Int) {
|
||||
val intent = ReviewTermsActivity.intent(fragment.requireContext(), serviceType, baseUrl, token)
|
||||
fragment.startActivityForResult(intent, requestCode)
|
||||
override fun openTerms(context: Context,
|
||||
activityResultLauncher: ActivityResultLauncher<Intent>,
|
||||
serviceType: TermsService.ServiceType,
|
||||
baseUrl: String,
|
||||
token: String?) {
|
||||
val intent = ReviewTermsActivity.intent(context, serviceType, baseUrl, token)
|
||||
activityResultLauncher.launch(intent)
|
||||
}
|
||||
|
||||
override fun openStickerPicker(fragment: Fragment, roomId: String, widget: Widget, requestCode: Int) {
|
||||
override fun openStickerPicker(context: Context,
|
||||
activityResultLauncher: ActivityResultLauncher<Intent>,
|
||||
roomId: String,
|
||||
widget: Widget) {
|
||||
val widgetArgs = widgetArgsBuilder.buildStickerPickerArgs(roomId, widget)
|
||||
val intent = WidgetActivity.newIntent(fragment.requireContext(), widgetArgs)
|
||||
fragment.startActivityForResult(intent, WidgetRequestCodes.STICKER_PICKER_REQUEST_CODE)
|
||||
val intent = WidgetActivity.newIntent(context, widgetArgs)
|
||||
activityResultLauncher.launch(intent)
|
||||
}
|
||||
|
||||
override fun openIntegrationManager(fragment: Fragment, roomId: String, integId: String?, screen: String?) {
|
||||
override fun openIntegrationManager(context: Context,
|
||||
activityResultLauncher: ActivityResultLauncher<Intent>,
|
||||
roomId: String,
|
||||
integId: String?,
|
||||
screen: String?) {
|
||||
val widgetArgs = widgetArgsBuilder.buildIntegrationManagerArgs(roomId, integId, screen)
|
||||
val intent = WidgetActivity.newIntent(fragment.requireContext(), widgetArgs)
|
||||
fragment.startActivityForResult(intent, WidgetRequestCodes.INTEGRATION_MANAGER_REQUEST_CODE)
|
||||
val intent = WidgetActivity.newIntent(context, widgetArgs)
|
||||
activityResultLauncher.launch(intent)
|
||||
}
|
||||
|
||||
override fun openRoomWidget(context: Context, roomId: String, widget: Widget, options: Map<String, Any>?) {
|
||||
|
@ -293,14 +303,11 @@ class DefaultNavigator @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun openPinCode(fragment: Fragment, pinMode: PinMode, requestCode: Int) {
|
||||
val intent = PinActivity.newIntent(fragment.requireContext(), PinArgs(pinMode))
|
||||
fragment.startActivityForResult(intent, requestCode)
|
||||
}
|
||||
|
||||
override fun openPinCode(activity: Activity, pinMode: PinMode, requestCode: Int) {
|
||||
val intent = PinActivity.newIntent(activity, PinArgs(pinMode))
|
||||
activity.startActivityForResult(intent, requestCode)
|
||||
override fun openPinCode(context: Context,
|
||||
activityResultLauncher: ActivityResultLauncher<Intent>,
|
||||
pinMode: PinMode) {
|
||||
val intent = PinActivity.newIntent(context, PinArgs(pinMode))
|
||||
activityResultLauncher.launch(intent)
|
||||
}
|
||||
|
||||
override fun openMediaViewer(activity: Activity,
|
||||
|
|
|
@ -18,18 +18,16 @@ package im.vector.app.features.navigation
|
|||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.view.View
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.core.util.Pair
|
||||
import androidx.fragment.app.Fragment
|
||||
import im.vector.app.features.crypto.recover.SetupMode
|
||||
import im.vector.app.features.home.room.detail.widget.WidgetRequestCodes
|
||||
import im.vector.app.features.media.AttachmentData
|
||||
import im.vector.app.features.pin.PinActivity
|
||||
import im.vector.app.features.pin.PinMode
|
||||
import im.vector.app.features.roomdirectory.roompreview.RoomPreviewData
|
||||
import im.vector.app.features.settings.VectorSettingsActivity
|
||||
import im.vector.app.features.share.SharedData
|
||||
import im.vector.app.features.terms.ReviewTermsActivity
|
||||
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
|
||||
import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData
|
||||
import org.matrix.android.sdk.api.session.terms.TermsService
|
||||
|
@ -84,22 +82,26 @@ interface Navigator {
|
|||
|
||||
fun openBigImageViewer(activity: Activity, sharedElement: View?, matrixItem: MatrixItem)
|
||||
|
||||
fun openPinCode(fragment: Fragment, pinMode: PinMode, requestCode: Int = PinActivity.PIN_REQUEST_CODE)
|
||||
fun openPinCode(context: Context,
|
||||
activityResultLauncher: ActivityResultLauncher<Intent>,
|
||||
pinMode: PinMode)
|
||||
|
||||
fun openPinCode(activity: Activity, pinMode: PinMode, requestCode: Int = PinActivity.PIN_REQUEST_CODE)
|
||||
|
||||
fun openTerms(fragment: Fragment,
|
||||
fun openTerms(context: Context,
|
||||
activityResultLauncher: ActivityResultLauncher<Intent>,
|
||||
serviceType: TermsService.ServiceType,
|
||||
baseUrl: String,
|
||||
token: String?,
|
||||
requestCode: Int = ReviewTermsActivity.TERMS_REQUEST_CODE)
|
||||
token: String?)
|
||||
|
||||
fun openStickerPicker(fragment: Fragment,
|
||||
fun openStickerPicker(context: Context,
|
||||
activityResultLauncher: ActivityResultLauncher<Intent>,
|
||||
roomId: String,
|
||||
widget: Widget,
|
||||
requestCode: Int = WidgetRequestCodes.STICKER_PICKER_REQUEST_CODE)
|
||||
widget: Widget)
|
||||
|
||||
fun openIntegrationManager(fragment: Fragment, roomId: String, integId: String?, screen: String?)
|
||||
fun openIntegrationManager(context: Context,
|
||||
activityResultLauncher: ActivityResultLauncher<Intent>,
|
||||
roomId: String,
|
||||
integId: String?,
|
||||
screen: String?)
|
||||
|
||||
fun openRoomWidget(context: Context, roomId: String, widget: Widget, options: Map<String, Any>? = null)
|
||||
|
||||
|
|
|
@ -28,8 +28,6 @@ import im.vector.app.core.platform.VectorBaseActivity
|
|||
class PinActivity : VectorBaseActivity(), ToolbarConfigurable, UnlockedActivity {
|
||||
|
||||
companion object {
|
||||
const val PIN_REQUEST_CODE = 17890
|
||||
|
||||
fun newIntent(context: Context, args: PinArgs): Intent {
|
||||
return Intent(context, PinActivity::class.java).apply {
|
||||
putExtra(MvRx.KEY_ARG, args)
|
||||
|
|
|
@ -19,7 +19,7 @@ package im.vector.app.features.qrcode
|
|||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import com.google.zxing.BarcodeFormat
|
||||
import com.google.zxing.Result
|
||||
import com.google.zxing.ResultMetadataType
|
||||
|
@ -75,15 +75,8 @@ class QrCodeScannerActivity : VectorBaseActivity() {
|
|||
private const val EXTRA_OUT_TEXT = "EXTRA_OUT_TEXT"
|
||||
private const val EXTRA_OUT_IS_QR_CODE = "EXTRA_OUT_IS_QR_CODE"
|
||||
|
||||
const val QR_CODE_SCANNER_REQUEST_CODE = 429
|
||||
|
||||
// For test only
|
||||
fun startForResult(activity: Activity, requestCode: Int = QR_CODE_SCANNER_REQUEST_CODE) {
|
||||
activity.startActivityForResult(Intent(activity, QrCodeScannerActivity::class.java), requestCode)
|
||||
}
|
||||
|
||||
fun startForResult(fragment: Fragment, requestCode: Int = QR_CODE_SCANNER_REQUEST_CODE) {
|
||||
fragment.startActivityForResult(Intent(fragment.requireActivity(), QrCodeScannerActivity::class.java), requestCode)
|
||||
fun startForResult(activity: Activity, activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||
activityResultLauncher.launch(Intent(activity, QrCodeScannerActivity::class.java))
|
||||
}
|
||||
|
||||
fun getResultText(data: Intent?): String? {
|
||||
|
|
|
@ -17,7 +17,6 @@ package im.vector.app.features.reactions
|
|||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.lifecycle.observe
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
|
|
|
@ -212,10 +212,8 @@ class EmojiReactionPickerActivity : VectorBaseActivity(),
|
|||
return intent
|
||||
}
|
||||
|
||||
fun getOutput(data: Intent): Pair<String, String>? {
|
||||
val eventId = data.getStringExtra(EXTRA_EVENT_ID) ?: return null
|
||||
val reaction = data.getStringExtra(EXTRA_REACTION_RESULT) ?: return null
|
||||
return eventId to reaction
|
||||
}
|
||||
fun getOutputEventId(data: Intent?): String? = data?.getStringExtra(EXTRA_EVENT_ID)
|
||||
|
||||
fun getOutputReaction(data: Intent?): String? = data?.getStringExtra(EXTRA_REACTION_RESULT)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -284,7 +284,12 @@ class RoomMemberProfileFragment @Inject constructor(
|
|||
}
|
||||
|
||||
private fun handleShareRoomMemberProfile(permalink: String) {
|
||||
startSharePlainTextIntent(fragment = this, chooserTitle = null, text = permalink)
|
||||
startSharePlainTextIntent(
|
||||
fragment = this,
|
||||
activityResultLauncher = null,
|
||||
chooserTitle = null,
|
||||
text = permalink
|
||||
)
|
||||
}
|
||||
|
||||
private fun onAvatarClicked(view: View, userMatrixItem: MatrixItem) {
|
||||
|
|
|
@ -20,6 +20,7 @@ import android.content.DialogInterface
|
|||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.KeyEvent
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.airbnb.mvrx.MvRx
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
|
@ -46,8 +47,8 @@ class DeviceListBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||
injector.inject(this)
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
viewModel.observeViewEvents {
|
||||
when (it) {
|
||||
is DeviceListBottomSheetViewEvents.Verify -> {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package im.vector.app.features.roommemberprofile.devices
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import butterknife.BindView
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
|
@ -41,8 +42,8 @@ class DeviceListFragment @Inject constructor(
|
|||
@BindView(R.id.bottomSheetRecyclerView)
|
||||
lateinit var recyclerView: RecyclerView
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
recyclerView.setPadding(0, dimensionConverter.dpToPx(16), 0, dimensionConverter.dpToPx(16))
|
||||
recyclerView.configureWith(
|
||||
epoxyController,
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package im.vector.app.features.roommemberprofile.devices
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import butterknife.BindView
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
|
@ -41,8 +42,8 @@ class DeviceTrustInfoActionFragment @Inject constructor(
|
|||
@BindView(R.id.bottomSheetRecyclerView)
|
||||
lateinit var recyclerView: RecyclerView
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
recyclerView.setPadding(0, dimensionConverter.dpToPx(16), 0, dimensionConverter.dpToPx(16))
|
||||
recyclerView.configureWith(
|
||||
epoxyController,
|
||||
|
|
|
@ -42,14 +42,14 @@ import im.vector.app.core.extensions.cleanup
|
|||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.extensions.copyOnLongClick
|
||||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.extensions.setTextOrHide
|
||||
import im.vector.app.core.intent.getFilenameFromUri
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
||||
import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA
|
||||
import im.vector.app.core.utils.allGranted
|
||||
import im.vector.app.core.utils.checkPermissions
|
||||
import im.vector.app.core.utils.copyToClipboard
|
||||
import im.vector.app.core.utils.registerForPermissionsResult
|
||||
import im.vector.app.core.utils.startSharePlainTextIntent
|
||||
import im.vector.app.features.crypto.util.toImageRes
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
|
@ -260,14 +260,19 @@ class RoomProfileFragment @Inject constructor(
|
|||
}
|
||||
|
||||
private fun onShareRoomProfile(permalink: String) {
|
||||
startSharePlainTextIntent(fragment = this, chooserTitle = null, text = permalink)
|
||||
startSharePlainTextIntent(
|
||||
fragment = this,
|
||||
activityResultLauncher = null,
|
||||
chooserTitle = null,
|
||||
text = permalink
|
||||
)
|
||||
}
|
||||
|
||||
private fun onAvatarClicked(view: View, matrixItem: MatrixItem.RoomItem) = withState(roomProfileViewModel) {
|
||||
if (matrixItem.avatarUrl?.isNotEmpty() == true) {
|
||||
val intent = BigImageViewerActivity.newIntent(requireContext(), matrixItem.getBestName(), matrixItem.avatarUrl!!, it.canChangeAvatar)
|
||||
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(requireActivity(), view, ViewCompat.getTransitionName(view) ?: "")
|
||||
startActivityForResult(intent, BigImageViewerActivity.REQUEST_CODE, options.toBundle())
|
||||
bigImageStartForActivityResult.launch(intent, options)
|
||||
} else if (it.canChangeAvatar) {
|
||||
showAvatarSelector()
|
||||
}
|
||||
|
@ -285,14 +290,20 @@ class RoomProfileFragment @Inject constructor(
|
|||
.show()
|
||||
}
|
||||
|
||||
private val takePhotoPermissionActivityResultLauncher = registerForPermissionsResult { allGranted ->
|
||||
if (allGranted) {
|
||||
onAvatarTypeSelected(true)
|
||||
}
|
||||
}
|
||||
|
||||
private var avatarCameraUri: Uri? = null
|
||||
private fun onAvatarTypeSelected(isCamera: Boolean) {
|
||||
if (isCamera) {
|
||||
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this, PERMISSION_REQUEST_CODE_LAUNCH_CAMERA)) {
|
||||
avatarCameraUri = MultiPicker.get(MultiPicker.CAMERA).startWithExpectingFile(this)
|
||||
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), takePhotoPermissionActivityResultLauncher)) {
|
||||
avatarCameraUri = MultiPicker.get(MultiPicker.CAMERA).startWithExpectingFile(requireActivity(), takePhotoActivityResultLauncher)
|
||||
}
|
||||
} else {
|
||||
MultiPicker.get(MultiPicker.IMAGE).single().startWith(this)
|
||||
MultiPicker.get(MultiPicker.IMAGE).single().startWith(pickImageActivityResultLauncher)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,37 +315,43 @@ class RoomProfileFragment @Inject constructor(
|
|||
.start(requireContext(), this)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
when (requestCode) {
|
||||
MultiPicker.REQUEST_CODE_TAKE_PHOTO -> {
|
||||
avatarCameraUri?.let { uri ->
|
||||
MultiPicker.get(MultiPicker.CAMERA)
|
||||
.getTakenPhoto(requireContext(), requestCode, resultCode, uri)
|
||||
?.let {
|
||||
onRoomAvatarSelected(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
MultiPicker.REQUEST_CODE_PICK_IMAGE -> {
|
||||
MultiPicker
|
||||
.get(MultiPicker.IMAGE)
|
||||
.getSelectedFiles(requireContext(), requestCode, resultCode, data)
|
||||
.firstOrNull()?.let {
|
||||
onRoomAvatarSelected(it)
|
||||
}
|
||||
}
|
||||
UCrop.REQUEST_CROP -> data?.let { onAvatarCropped(UCrop.getOutput(it)) }
|
||||
BigImageViewerActivity.REQUEST_CODE -> data?.let { onAvatarCropped(it.data) }
|
||||
private val takePhotoActivityResultLauncher = registerStartForActivityResult { activityResult ->
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
avatarCameraUri?.let { uri ->
|
||||
MultiPicker.get(MultiPicker.CAMERA)
|
||||
.getTakenPhoto(requireContext(), uri)
|
||||
?.let {
|
||||
onRoomAvatarSelected(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||
if (allGranted(grantResults)) {
|
||||
private val pickImageActivityResultLauncher = registerStartForActivityResult { activityResult ->
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
MultiPicker
|
||||
.get(MultiPicker.IMAGE)
|
||||
.getSelectedFiles(requireContext(), activityResult.data)
|
||||
.firstOrNull()?.let {
|
||||
onRoomAvatarSelected(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val bigImageStartForActivityResult = registerStartForActivityResult { activityResult ->
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
activityResult.data?.let { onAvatarCropped(it.data) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
// TODO handle this one (Ucrop lib)
|
||||
@Suppress("DEPRECATION")
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
when (requestCode) {
|
||||
PERMISSION_REQUEST_CODE_LAUNCH_CAMERA -> onAvatarTypeSelected(true)
|
||||
UCrop.REQUEST_CROP -> data?.let { onAvatarCropped(UCrop.getOutput(it)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,7 +107,8 @@ class VectorSettingsActivity : VectorBaseActivity(),
|
|||
}
|
||||
|
||||
if (oFragment != null) {
|
||||
oFragment.setTargetFragment(caller, 0)
|
||||
// Deprecated, I comment it, I think it is useless
|
||||
// oFragment.setTargetFragment(caller, 0)
|
||||
// Replace the existing Fragment with the new Fragment
|
||||
supportFragmentManager.beginTransaction()
|
||||
.setCustomAnimations(R.anim.right_in, R.anim.fade_out, R.anim.fade_in, R.anim.right_out)
|
||||
|
|
|
@ -41,6 +41,7 @@ import com.google.android.material.textfield.TextInputLayout
|
|||
import com.yalantis.ucrop.UCrop
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.hideKeyboard
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.extensions.showPassword
|
||||
import im.vector.app.core.intent.getFilenameFromUri
|
||||
import im.vector.app.core.platform.SimpleTextWatcher
|
||||
|
@ -48,11 +49,10 @@ import im.vector.app.core.preference.UserAvatarPreference
|
|||
import im.vector.app.core.preference.VectorPreference
|
||||
import im.vector.app.core.preference.VectorSwitchPreference
|
||||
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
||||
import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA
|
||||
import im.vector.app.core.utils.TextUtils
|
||||
import im.vector.app.core.utils.allGranted
|
||||
import im.vector.app.core.utils.checkPermissions
|
||||
import im.vector.app.core.utils.getSizeOfFiles
|
||||
import im.vector.app.core.utils.registerForPermissionsResult
|
||||
import im.vector.app.core.utils.toast
|
||||
import im.vector.app.features.MainActivity
|
||||
import im.vector.app.features.MainActivityArgs
|
||||
|
@ -279,89 +279,38 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
|
|||
session.integrationManagerService().removeListener(integrationServiceListener)
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
||||
if (allGranted(grantResults)) {
|
||||
if (requestCode == PERMISSION_REQUEST_CODE_LAUNCH_CAMERA) {
|
||||
onAvatarTypeSelected(true)
|
||||
private val attachmentPhotoActivityResultLauncher = registerStartForActivityResult { activityResult ->
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
avatarCameraUri?.let { uri ->
|
||||
MultiPicker.get(MultiPicker.CAMERA)
|
||||
.getTakenPhoto(requireContext(), uri)
|
||||
?.let {
|
||||
onAvatarSelected(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val attachmentImageActivityResultLauncher = registerStartForActivityResult { activityResult ->
|
||||
val data = activityResult.data ?: return@registerStartForActivityResult
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
MultiPicker
|
||||
.get(MultiPicker.IMAGE)
|
||||
.getSelectedFiles(requireContext(), data)
|
||||
.firstOrNull()?.let {
|
||||
onAvatarSelected(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
// TODO handle this one (Ucrop lib)
|
||||
@Suppress("DEPRECATION")
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
when (requestCode) {
|
||||
REQUEST_NEW_PHONE_NUMBER -> refreshPhoneNumbersList()
|
||||
REQUEST_PHONEBOOK_COUNTRY -> onPhonebookCountryUpdate(data)
|
||||
MultiPicker.REQUEST_CODE_TAKE_PHOTO -> {
|
||||
avatarCameraUri?.let { uri ->
|
||||
MultiPicker.get(MultiPicker.CAMERA)
|
||||
.getTakenPhoto(requireContext(), requestCode, resultCode, uri)
|
||||
?.let {
|
||||
onAvatarSelected(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
MultiPicker.REQUEST_CODE_PICK_IMAGE -> {
|
||||
MultiPicker
|
||||
.get(MultiPicker.IMAGE)
|
||||
.getSelectedFiles(requireContext(), requestCode, resultCode, data)
|
||||
.firstOrNull()?.let {
|
||||
onAvatarSelected(it)
|
||||
}
|
||||
}
|
||||
UCrop.REQUEST_CROP -> data?.let { onAvatarCropped(UCrop.getOutput(it)) }
|
||||
/* TODO
|
||||
VectorUtils.TAKE_IMAGE -> {
|
||||
val thumbnailUri = VectorUtils.getThumbnailUriFromIntent(activity, data, session.mediaCache)
|
||||
|
||||
if (null != thumbnailUri) {
|
||||
displayLoadingView()
|
||||
|
||||
val resource = ResourceUtils.openResource(activity, thumbnailUri, null)
|
||||
|
||||
if (null != resource) {
|
||||
session.mediaCache.uploadContent(resource.mContentStream, null, resource.mMimeType, null, object : MXMediaUploadListener() {
|
||||
|
||||
override fun onUploadError(uploadId: String?, serverResponseCode: Int, serverErrorMessage: String?) {
|
||||
activity?.runOnUiThread { onCommonDone(serverResponseCode.toString() + " : " + serverErrorMessage) }
|
||||
}
|
||||
|
||||
override fun onUploadComplete(uploadId: String?, contentUri: String?) {
|
||||
activity?.runOnUiThread {
|
||||
session.myUser.updateAvatarUrl(contentUri, object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(info: Void?) {
|
||||
onCommonDone(null)
|
||||
refreshDisplay()
|
||||
}
|
||||
|
||||
override fun onNetworkError(e: Exception) {
|
||||
onCommonDone(e.localizedMessage)
|
||||
}
|
||||
|
||||
override fun onMatrixError(e: MatrixError) {
|
||||
if (MatrixError.M_CONSENT_NOT_GIVEN == e.errcode) {
|
||||
activity?.runOnUiThread {
|
||||
hideLoadingView()
|
||||
(activity as VectorAppCompatActivity).consentNotGivenHelper.displayDialog(e)
|
||||
}
|
||||
} else {
|
||||
onCommonDone(e.localizedMessage)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUnexpectedError(e: Exception) {
|
||||
onCommonDone(e.localizedMessage)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
UCrop.REQUEST_CROP -> data?.let { onAvatarCropped(UCrop.getOutput(it)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -400,13 +349,19 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
|
|||
}.show()
|
||||
}
|
||||
|
||||
private val takePhotoActivityResultLauncher = registerForPermissionsResult { allGranted ->
|
||||
if (allGranted) {
|
||||
onAvatarTypeSelected(true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onAvatarTypeSelected(isCamera: Boolean) {
|
||||
if (isCamera) {
|
||||
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this, PERMISSION_REQUEST_CODE_LAUNCH_CAMERA)) {
|
||||
avatarCameraUri = MultiPicker.get(MultiPicker.CAMERA).startWithExpectingFile(this)
|
||||
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), takePhotoActivityResultLauncher)) {
|
||||
avatarCameraUri = MultiPicker.get(MultiPicker.CAMERA).startWithExpectingFile(requireActivity(), attachmentPhotoActivityResultLauncher)
|
||||
}
|
||||
} else {
|
||||
MultiPicker.get(MultiPicker.IMAGE).single().startWith(this)
|
||||
MultiPicker.get(MultiPicker.IMAGE).single().startWith(attachmentImageActivityResultLauncher)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -464,29 +419,10 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
|
|||
*/
|
||||
}
|
||||
|
||||
private fun onPhonebookCountryUpdate(data: Intent?) {
|
||||
/* TODO
|
||||
if (data != null && data.hasExtra(CountryPickerActivity.EXTRA_OUT_COUNTRY_NAME)
|
||||
&& data.hasExtra(CountryPickerActivity.EXTRA_OUT_COUNTRY_CODE)) {
|
||||
val countryCode = data.getStringExtra(CountryPickerActivity.EXTRA_OUT_COUNTRY_CODE)
|
||||
if (!TextUtils.equals(countryCode, PhoneNumberUtils.getCountryCode(activity))) {
|
||||
PhoneNumberUtils.setCountryCode(activity, countryCode)
|
||||
mContactPhonebookCountryPreference.summary = data.getStringExtra(CountryPickerActivity.EXTRA_OUT_COUNTRY_NAME)
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// ==============================================================================================================
|
||||
// Phone number management
|
||||
// ==============================================================================================================
|
||||
|
||||
/**
|
||||
* Refresh phone number list
|
||||
*/
|
||||
private fun refreshPhoneNumbersList() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the password.
|
||||
*/
|
||||
|
@ -646,9 +582,4 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val REQUEST_NEW_PHONE_NUMBER = 456
|
||||
private const val REQUEST_PHONEBOOK_COUNTRY = 789
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import androidx.preference.Preference
|
|||
import androidx.preference.SwitchPreference
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.di.ActiveSessionHolder
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.preference.VectorEditTextPreference
|
||||
import im.vector.app.core.preference.VectorPreference
|
||||
import im.vector.app.core.preference.VectorPreferenceCategory
|
||||
|
@ -114,6 +115,10 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor(
|
|||
handleSystemPreference()
|
||||
}
|
||||
|
||||
private val batteryStartForActivityResult = registerStartForActivityResult {
|
||||
// Noop
|
||||
}
|
||||
|
||||
// BackgroundSyncModeChooserDialog.InteractionListener
|
||||
override fun onOptionSelected(mode: BackgroundSyncMode) {
|
||||
// option has change, need to act
|
||||
|
@ -122,9 +127,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor(
|
|||
// Even if using foreground service with foreground notif, it stops to work
|
||||
// in doze mode for certain devices :/
|
||||
if (!isIgnoringBatteryOptimizations(requireContext())) {
|
||||
requestDisablingBatteryOptimization(requireActivity(),
|
||||
this@VectorSettingsNotificationPreferenceFragment,
|
||||
REQUEST_BATTERY_OPTIMIZATION)
|
||||
requestDisablingBatteryOptimization(requireActivity(), batteryStartForActivityResult)
|
||||
}
|
||||
}
|
||||
vectorPreferences.setFdroidSyncBackgroundMode(mode)
|
||||
|
@ -210,27 +213,22 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor(
|
|||
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, vectorPreferences.getNotificationRingTone())
|
||||
}
|
||||
|
||||
startActivityForResult(intent, REQUEST_NOTIFICATION_RINGTONE)
|
||||
ringtoneStartForActivityResult.launch(intent)
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
when (requestCode) {
|
||||
REQUEST_NOTIFICATION_RINGTONE -> {
|
||||
vectorPreferences.setNotificationRingTone(data?.getParcelableExtra<Parcelable>(RingtoneManager.EXTRA_RINGTONE_PICKED_URI) as Uri?)
|
||||
private val ringtoneStartForActivityResult = registerStartForActivityResult { activityResult ->
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
vectorPreferences.setNotificationRingTone(activityResult.data?.getParcelableExtra<Parcelable>(RingtoneManager.EXTRA_RINGTONE_PICKED_URI) as Uri?)
|
||||
|
||||
// test if the selected ring tone can be played
|
||||
val notificationRingToneName = vectorPreferences.getNotificationRingToneName()
|
||||
if (null != notificationRingToneName) {
|
||||
vectorPreferences.setNotificationRingTone(vectorPreferences.getNotificationRingTone())
|
||||
findPreference<VectorPreference>(VectorPreferences.SETTINGS_NOTIFICATION_RINGTONE_SELECTION_PREFERENCE_KEY)!!
|
||||
.summary = notificationRingToneName
|
||||
}
|
||||
}
|
||||
// test if the selected ring tone can be played
|
||||
val notificationRingToneName = vectorPreferences.getNotificationRingToneName()
|
||||
if (null != notificationRingToneName) {
|
||||
vectorPreferences.setNotificationRingTone(vectorPreferences.getNotificationRingTone())
|
||||
findPreference<VectorPreference>(VectorPreferences.SETTINGS_NOTIFICATION_RINGTONE_SELECTION_PREFERENCE_KEY)!!
|
||||
.summary = notificationRingToneName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -340,9 +338,4 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor(
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val REQUEST_NOTIFICATION_RINGTONE = 888
|
||||
private const val REQUEST_BATTERY_OPTIMIZATION = 500
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ package im.vector.app.features.settings
|
|||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
@ -30,6 +29,7 @@ import androidx.transition.TransitionManager
|
|||
import butterknife.BindView
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.features.rageshake.BugReporter
|
||||
|
@ -76,7 +76,7 @@ class VectorSettingsNotificationsTroubleshootFragment @Inject constructor(
|
|||
}
|
||||
|
||||
mRunButton.debouncedClicks {
|
||||
testManager?.retry()
|
||||
testManager?.retry(testStartForActivityResult)
|
||||
}
|
||||
startUI()
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ class VectorSettingsNotificationsTroubleshootFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
mRecyclerView.adapter = testManager?.adapter
|
||||
testManager?.runDiagnostic()
|
||||
testManager?.runDiagnostic(testStartForActivityResult)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
@ -142,12 +142,14 @@ class VectorSettingsNotificationsTroubleshootFragment @Inject constructor(
|
|||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (resultCode == Activity.RESULT_OK && requestCode == NotificationTroubleshootTestManager.REQ_CODE_FIX) {
|
||||
testManager?.retry()
|
||||
return
|
||||
private val testStartForActivityResult = registerStartForActivityResult { activityResult ->
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
retry()
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
private fun retry() {
|
||||
testManager?.retry(testStartForActivityResult)
|
||||
}
|
||||
|
||||
override fun onDetach() {
|
||||
|
|
|
@ -16,14 +16,13 @@
|
|||
|
||||
package im.vector.app.features.settings
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.SwitchPreference
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.features.navigation.Navigator
|
||||
import im.vector.app.features.notifications.NotificationDrawerManager
|
||||
import im.vector.app.features.pin.PinActivity
|
||||
import im.vector.app.features.pin.PinCodeStore
|
||||
import im.vector.app.features.pin.PinMode
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -67,17 +66,18 @@ class VectorSettingsPinFragment @Inject constructor(
|
|||
refreshPinCodeStatus()
|
||||
}
|
||||
} else {
|
||||
navigator.openPinCode(this@VectorSettingsPinFragment, PinMode.CREATE)
|
||||
navigator.openPinCode(
|
||||
requireContext(),
|
||||
pinActivityResultLauncher,
|
||||
PinMode.CREATE
|
||||
)
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (requestCode == PinActivity.PIN_REQUEST_CODE) {
|
||||
refreshPinCodeStatus()
|
||||
}
|
||||
private val pinActivityResultLauncher = registerStartForActivityResult {
|
||||
refreshPinCodeStatus()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ import im.vector.app.R
|
|||
import im.vector.app.core.di.ActiveSessionHolder
|
||||
import im.vector.app.core.dialogs.ExportKeysDialog
|
||||
import im.vector.app.core.extensions.queryExportKeys
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.extensions.showPassword
|
||||
import im.vector.app.core.intent.ExternalIntentData
|
||||
import im.vector.app.core.intent.analyseIntent
|
||||
|
@ -55,7 +56,6 @@ import im.vector.app.features.crypto.keysbackup.settings.KeysBackupManageActivit
|
|||
import im.vector.app.features.crypto.recover.BootstrapBottomSheet
|
||||
import im.vector.app.features.crypto.recover.SetupMode
|
||||
import im.vector.app.features.navigation.Navigator
|
||||
import im.vector.app.features.pin.PinActivity
|
||||
import im.vector.app.features.pin.PinCodeStore
|
||||
import im.vector.app.features.pin.PinMode
|
||||
import im.vector.app.features.raw.wellknown.getElementWellknown
|
||||
|
@ -320,48 +320,46 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
when (requestCode) {
|
||||
REQUEST_CODE_SAVE_MEGOLM_EXPORT -> {
|
||||
val uri = data?.data
|
||||
if (uri != null) {
|
||||
activity?.let { activity ->
|
||||
ExportKeysDialog().show(activity, object : ExportKeysDialog.ExportKeyDialogListener {
|
||||
override fun onPassphrase(passphrase: String) {
|
||||
displayLoadingView()
|
||||
private val saveMegolmStartForActivityResult = registerStartForActivityResult {
|
||||
val uri = it.data?.data ?: return@registerStartForActivityResult
|
||||
if (it.resultCode == Activity.RESULT_OK) {
|
||||
ExportKeysDialog().show(requireActivity(), object : ExportKeysDialog.ExportKeyDialogListener {
|
||||
override fun onPassphrase(passphrase: String) {
|
||||
displayLoadingView()
|
||||
|
||||
KeysExporter(session)
|
||||
.export(requireContext(),
|
||||
passphrase,
|
||||
uri,
|
||||
object : MatrixCallback<Boolean> {
|
||||
override fun onSuccess(data: Boolean) {
|
||||
if (data) {
|
||||
requireActivity().toast(getString(R.string.encryption_exported_successfully))
|
||||
} else {
|
||||
requireActivity().toast(getString(R.string.unexpected_error))
|
||||
}
|
||||
hideLoadingView()
|
||||
}
|
||||
KeysExporter(session)
|
||||
.export(requireContext(),
|
||||
passphrase,
|
||||
uri,
|
||||
object : MatrixCallback<Boolean> {
|
||||
override fun onSuccess(data: Boolean) {
|
||||
if (data) {
|
||||
requireActivity().toast(getString(R.string.encryption_exported_successfully))
|
||||
} else {
|
||||
requireActivity().toast(getString(R.string.unexpected_error))
|
||||
}
|
||||
hideLoadingView()
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
onCommonDone(failure.localizedMessage)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
override fun onFailure(failure: Throwable) {
|
||||
onCommonDone(failure.localizedMessage)
|
||||
}
|
||||
})
|
||||
}
|
||||
PinActivity.PIN_REQUEST_CODE -> {
|
||||
doOpenPinCodePreferenceScreen()
|
||||
}
|
||||
REQUEST_E2E_FILE_REQUEST_CODE -> {
|
||||
importKeys(data)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private val pinActivityResultLauncher = registerStartForActivityResult {
|
||||
if (it.resultCode == Activity.RESULT_OK) {
|
||||
doOpenPinCodePreferenceScreen()
|
||||
}
|
||||
}
|
||||
|
||||
private val importKeysActivityResultLauncher = registerStartForActivityResult {
|
||||
val data = it.data ?: return@registerStartForActivityResult
|
||||
if (it.resultCode == Activity.RESULT_OK) {
|
||||
importKeys(data)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -369,7 +367,10 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
|
|||
lifecycleScope.launchWhenResumed {
|
||||
val hasPinCode = pinCodeStore.hasEncodedPin()
|
||||
if (hasPinCode) {
|
||||
navigator.openPinCode(this@VectorSettingsSecurityPrivacyFragment, PinMode.AUTH)
|
||||
navigator.openPinCode(
|
||||
requireContext(),
|
||||
pinActivityResultLauncher,
|
||||
PinMode.AUTH)
|
||||
} else {
|
||||
doOpenPinCodePreferenceScreen()
|
||||
}
|
||||
|
@ -391,7 +392,7 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
|
|||
}
|
||||
|
||||
exportPref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
queryExportKeys(activeSessionHolder.getSafeActiveSession()?.myUserId ?: "", REQUEST_CODE_SAVE_MEGOLM_EXPORT)
|
||||
queryExportKeys(activeSessionHolder.getSafeActiveSession()?.myUserId ?: "", saveMegolmStartForActivityResult)
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -406,7 +407,12 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
|
|||
*/
|
||||
@SuppressLint("NewApi")
|
||||
private fun importKeys() {
|
||||
activity?.let { openFileSelection(it, this, false, REQUEST_E2E_FILE_REQUEST_CODE) }
|
||||
openFileSelection(
|
||||
requireActivity(),
|
||||
importKeysActivityResultLauncher,
|
||||
false,
|
||||
0
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -414,12 +420,7 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
|
|||
*
|
||||
* @param intent the intent result
|
||||
*/
|
||||
private fun importKeys(intent: Intent?) {
|
||||
// sanity check
|
||||
if (null == intent) {
|
||||
return
|
||||
}
|
||||
|
||||
private fun importKeys(intent: Intent) {
|
||||
val sharedDataItems = analyseIntent(intent)
|
||||
val thisActivity = activity
|
||||
|
||||
|
@ -605,9 +606,4 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val REQUEST_E2E_FILE_REQUEST_CODE = 123
|
||||
private const val REQUEST_CODE_SAVE_MEGOLM_EXPORT = 124
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue