mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-02-10 00:50:49 +01:00
Custom alert design
This commit is contained in:
parent
22642e71a3
commit
b56a41bec7
@ -323,7 +323,7 @@ dependencies {
|
|||||||
implementation 'com.nulab-inc:zxcvbn:1.2.7'
|
implementation 'com.nulab-inc:zxcvbn:1.2.7'
|
||||||
|
|
||||||
//Alerter
|
//Alerter
|
||||||
implementation 'com.tapadoo.android:alerter:4.0.3'
|
implementation 'com.tapadoo.android:alerter:5.1.2'
|
||||||
|
|
||||||
implementation 'com.otaliastudios:autocomplete:1.1.0'
|
implementation 'com.otaliastudios:autocomplete:1.1.0'
|
||||||
|
|
||||||
|
@ -48,6 +48,7 @@ import im.vector.riotx.features.lifecycle.VectorActivityLifecycleCallbacks
|
|||||||
import im.vector.riotx.features.notifications.NotificationDrawerManager
|
import im.vector.riotx.features.notifications.NotificationDrawerManager
|
||||||
import im.vector.riotx.features.notifications.NotificationUtils
|
import im.vector.riotx.features.notifications.NotificationUtils
|
||||||
import im.vector.riotx.features.notifications.PushRuleTriggerListener
|
import im.vector.riotx.features.notifications.PushRuleTriggerListener
|
||||||
|
import im.vector.riotx.features.popup.PopupAlertManager
|
||||||
import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler
|
import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler
|
||||||
import im.vector.riotx.features.session.SessionListener
|
import im.vector.riotx.features.session.SessionListener
|
||||||
import im.vector.riotx.features.settings.VectorPreferences
|
import im.vector.riotx.features.settings.VectorPreferences
|
||||||
@ -77,6 +78,7 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.
|
|||||||
@Inject lateinit var notificationUtils: NotificationUtils
|
@Inject lateinit var notificationUtils: NotificationUtils
|
||||||
@Inject lateinit var appStateHandler: AppStateHandler
|
@Inject lateinit var appStateHandler: AppStateHandler
|
||||||
@Inject lateinit var rxConfig: RxConfig
|
@Inject lateinit var rxConfig: RxConfig
|
||||||
|
@Inject lateinit var popupAlertManager: PopupAlertManager
|
||||||
lateinit var vectorComponent: VectorComponent
|
lateinit var vectorComponent: VectorComponent
|
||||||
private var fontThreadHandler: Handler? = null
|
private var fontThreadHandler: Handler? = null
|
||||||
|
|
||||||
@ -102,7 +104,7 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.
|
|||||||
BigImageViewer.initialize(GlideImageLoader.with(applicationContext))
|
BigImageViewer.initialize(GlideImageLoader.with(applicationContext))
|
||||||
EpoxyController.defaultDiffingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler()
|
EpoxyController.defaultDiffingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler()
|
||||||
EpoxyController.defaultModelBuildingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler()
|
EpoxyController.defaultModelBuildingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler()
|
||||||
registerActivityLifecycleCallbacks(VectorActivityLifecycleCallbacks())
|
registerActivityLifecycleCallbacks(VectorActivityLifecycleCallbacks(popupAlertManager))
|
||||||
val fontRequest = FontRequest(
|
val fontRequest = FontRequest(
|
||||||
"com.google.android.gms.fonts",
|
"com.google.android.gms.fonts",
|
||||||
"com.google.android.gms",
|
"com.google.android.gms",
|
||||||
|
@ -45,6 +45,7 @@ import im.vector.riotx.features.notifications.NotificationBroadcastReceiver
|
|||||||
import im.vector.riotx.features.notifications.NotificationDrawerManager
|
import im.vector.riotx.features.notifications.NotificationDrawerManager
|
||||||
import im.vector.riotx.features.notifications.NotificationUtils
|
import im.vector.riotx.features.notifications.NotificationUtils
|
||||||
import im.vector.riotx.features.notifications.PushRuleTriggerListener
|
import im.vector.riotx.features.notifications.PushRuleTriggerListener
|
||||||
|
import im.vector.riotx.features.popup.PopupAlertManager
|
||||||
import im.vector.riotx.features.rageshake.BugReporter
|
import im.vector.riotx.features.rageshake.BugReporter
|
||||||
import im.vector.riotx.features.rageshake.VectorFileLogger
|
import im.vector.riotx.features.rageshake.VectorFileLogger
|
||||||
import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler
|
import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler
|
||||||
@ -128,6 +129,8 @@ interface VectorComponent {
|
|||||||
|
|
||||||
fun emojiDataSource(): EmojiDataSource
|
fun emojiDataSource(): EmojiDataSource
|
||||||
|
|
||||||
|
fun alertManager() : PopupAlertManager
|
||||||
|
|
||||||
@Component.Factory
|
@Component.Factory
|
||||||
interface Factory {
|
interface Factory {
|
||||||
fun create(@BindsInstance context: Context): VectorComponent
|
fun create(@BindsInstance context: Context): VectorComponent
|
||||||
|
@ -36,7 +36,9 @@ import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
|||||||
import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
|
import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
|
||||||
import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse
|
import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
|
import im.vector.riotx.features.popup.DefaultVectorAlert
|
||||||
import im.vector.riotx.features.popup.PopupAlertManager
|
import im.vector.riotx.features.popup.PopupAlertManager
|
||||||
|
import im.vector.riotx.features.popup.VectorAlert
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
@ -54,7 +56,7 @@ import javax.inject.Singleton
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class KeyRequestHandler @Inject constructor(private val context: Context)
|
class KeyRequestHandler @Inject constructor(private val context: Context, private val popupAlertManager: PopupAlertManager)
|
||||||
: GossipingRequestListener,
|
: GossipingRequestListener,
|
||||||
VerificationService.Listener {
|
VerificationService.Listener {
|
||||||
|
|
||||||
@ -118,9 +120,9 @@ class KeyRequestHandler @Inject constructor(private val context: Context)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (deviceInfo.isUnknown) {
|
if (deviceInfo.isUnknown) {
|
||||||
session?.cryptoService()?.setDeviceVerification(DeviceTrustLevel(false, false), userId, deviceId)
|
session?.cryptoService()?.setDeviceVerification(DeviceTrustLevel(crossSigningVerified = false, locallyVerified = false), userId, deviceId)
|
||||||
|
|
||||||
deviceInfo.trustLevel = DeviceTrustLevel(false, false)
|
deviceInfo.trustLevel = DeviceTrustLevel(crossSigningVerified = false, locallyVerified = false)
|
||||||
|
|
||||||
// can we get more info on this device?
|
// can we get more info on this device?
|
||||||
session?.cryptoService()?.getDevicesList(object : MatrixCallback<DevicesListResponse> {
|
session?.cryptoService()?.getDevicesList(object : MatrixCallback<DevicesListResponse> {
|
||||||
@ -188,7 +190,7 @@ class KeyRequestHandler @Inject constructor(private val context: Context)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val alert = PopupAlertManager.VectorAlert(
|
val alert = DefaultVectorAlert(
|
||||||
alertManagerId(userId, deviceId),
|
alertManagerId(userId, deviceId),
|
||||||
context.getString(R.string.key_share_request),
|
context.getString(R.string.key_share_request),
|
||||||
dialogText,
|
dialogText,
|
||||||
@ -210,7 +212,7 @@ class KeyRequestHandler @Inject constructor(private val context: Context)
|
|||||||
denyAllRequests(mappingKey)
|
denyAllRequests(mappingKey)
|
||||||
})
|
})
|
||||||
|
|
||||||
PopupAlertManager.postVectorAlert(alert)
|
popupAlertManager.postVectorAlert(alert)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun denyAllRequests(mappingKey: String) {
|
private fun denyAllRequests(mappingKey: String) {
|
||||||
@ -250,7 +252,7 @@ class KeyRequestHandler @Inject constructor(private val context: Context)
|
|||||||
&& it.requestId == request.requestId
|
&& it.requestId == request.requestId
|
||||||
}
|
}
|
||||||
if (alertsToRequests[alertMgrUniqueKey]?.isEmpty() == true) {
|
if (alertsToRequests[alertMgrUniqueKey]?.isEmpty() == true) {
|
||||||
PopupAlertManager.cancelAlert(alertMgrUniqueKey)
|
popupAlertManager.cancelAlert(alertMgrUniqueKey)
|
||||||
alertsToRequests.remove(keyForMap(userId, deviceId))
|
alertsToRequests.remove(keyForMap(userId, deviceId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -261,7 +263,7 @@ class KeyRequestHandler @Inject constructor(private val context: Context)
|
|||||||
if (state == VerificationTxState.Verified) {
|
if (state == VerificationTxState.Verified) {
|
||||||
// ok it's verified, see if we have key request for that
|
// ok it's verified, see if we have key request for that
|
||||||
shareAllSessions("${tx.otherDeviceId}${tx.otherUserId}")
|
shareAllSessions("${tx.otherDeviceId}${tx.otherUserId}")
|
||||||
PopupAlertManager.cancelAlert("ikr_${tx.otherDeviceId}${tx.otherUserId}")
|
popupAlertManager.cancelAlert("ikr_${tx.otherDeviceId}${tx.otherUserId}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// should do it with QR tx also
|
// should do it with QR tx also
|
||||||
@ -271,7 +273,7 @@ class KeyRequestHandler @Inject constructor(private val context: Context)
|
|||||||
override fun markedAsManuallyVerified(userId: String, deviceId: String) {
|
override fun markedAsManuallyVerified(userId: String, deviceId: String) {
|
||||||
// accept related requests
|
// accept related requests
|
||||||
shareAllSessions(keyForMap(userId, deviceId))
|
shareAllSessions(keyForMap(userId, deviceId))
|
||||||
PopupAlertManager.cancelAlert(alertManagerId(userId, deviceId))
|
popupAlertManager.cancelAlert(alertManagerId(userId, deviceId))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun keyForMap(userId: String, deviceId: String) = "$deviceId$userId"
|
private fun keyForMap(userId: String, deviceId: String) = "$deviceId$userId"
|
||||||
|
@ -17,15 +17,17 @@ package im.vector.riotx.features.crypto.verification
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.matrix.android.api.session.Session
|
||||||
|
import im.vector.matrix.android.api.session.crypto.verification.PendingVerificationRequest
|
||||||
import im.vector.matrix.android.api.session.crypto.verification.VerificationService
|
import im.vector.matrix.android.api.session.crypto.verification.VerificationService
|
||||||
import im.vector.matrix.android.api.session.crypto.verification.VerificationTransaction
|
import im.vector.matrix.android.api.session.crypto.verification.VerificationTransaction
|
||||||
import im.vector.matrix.android.api.session.crypto.verification.VerificationTxState
|
import im.vector.matrix.android.api.session.crypto.verification.VerificationTxState
|
||||||
import im.vector.matrix.android.api.session.crypto.verification.PendingVerificationRequest
|
import im.vector.matrix.android.api.util.toMatrixItem
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
import im.vector.riotx.core.platform.VectorBaseActivity
|
import im.vector.riotx.core.platform.VectorBaseActivity
|
||||||
import im.vector.riotx.features.home.room.detail.RoomDetailActivity
|
import im.vector.riotx.features.home.room.detail.RoomDetailActivity
|
||||||
import im.vector.riotx.features.home.room.detail.RoomDetailArgs
|
import im.vector.riotx.features.home.room.detail.RoomDetailArgs
|
||||||
import im.vector.riotx.features.popup.PopupAlertManager
|
import im.vector.riotx.features.popup.PopupAlertManager
|
||||||
|
import im.vector.riotx.features.popup.VerificationVectorAlert
|
||||||
import im.vector.riotx.features.themes.ThemeUtils
|
import im.vector.riotx.features.themes.ThemeUtils
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
@ -34,7 +36,9 @@ import javax.inject.Singleton
|
|||||||
* Listens to the VerificationManager and add a new notification when an incoming request is detected.
|
* Listens to the VerificationManager and add a new notification when an incoming request is detected.
|
||||||
*/
|
*/
|
||||||
@Singleton
|
@Singleton
|
||||||
class IncomingVerificationRequestHandler @Inject constructor(private val context: Context) : VerificationService.Listener {
|
class IncomingVerificationRequestHandler @Inject constructor(
|
||||||
|
private val context: Context,
|
||||||
|
private val popupAlertManager: PopupAlertManager) : VerificationService.Listener {
|
||||||
|
|
||||||
private var session: Session? = null
|
private var session: Session? = null
|
||||||
|
|
||||||
@ -58,7 +62,7 @@ class IncomingVerificationRequestHandler @Inject constructor(private val context
|
|||||||
val name = session?.getUser(tx.otherUserId)?.displayName
|
val name = session?.getUser(tx.otherUserId)?.displayName
|
||||||
?: tx.otherUserId
|
?: tx.otherUserId
|
||||||
|
|
||||||
val alert = PopupAlertManager.VectorAlert(
|
val alert = VerificationVectorAlert(
|
||||||
uid,
|
uid,
|
||||||
context.getString(R.string.sas_incoming_request_notif_title),
|
context.getString(R.string.sas_incoming_request_notif_title),
|
||||||
context.getString(R.string.sas_incoming_request_notif_content, name),
|
context.getString(R.string.sas_incoming_request_notif_content, name),
|
||||||
@ -68,12 +72,15 @@ class IncomingVerificationRequestHandler @Inject constructor(private val context
|
|||||||
// TODO a bit too hugly :/
|
// TODO a bit too hugly :/
|
||||||
activity.supportFragmentManager.findFragmentByTag(VerificationBottomSheet.WAITING_SELF_VERIF_TAG)?.let {
|
activity.supportFragmentManager.findFragmentByTag(VerificationBottomSheet.WAITING_SELF_VERIF_TAG)?.let {
|
||||||
false.also {
|
false.also {
|
||||||
PopupAlertManager.cancelAlert(uid)
|
popupAlertManager.cancelAlert(uid)
|
||||||
}
|
}
|
||||||
} ?: true
|
} ?: true
|
||||||
} else true
|
} else true
|
||||||
})
|
})
|
||||||
.apply {
|
.apply {
|
||||||
|
|
||||||
|
matrixItem = session?.getUser(tx.otherUserId ?: "")?.toMatrixItem()
|
||||||
|
|
||||||
contentAction = Runnable {
|
contentAction = Runnable {
|
||||||
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
|
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
|
||||||
it.navigator.performDeviceVerification(it, tx.otherUserId, tx.transactionId)
|
it.navigator.performDeviceVerification(it, tx.otherUserId, tx.transactionId)
|
||||||
@ -99,11 +106,11 @@ class IncomingVerificationRequestHandler @Inject constructor(private val context
|
|||||||
// 10mn expiration
|
// 10mn expiration
|
||||||
expirationTimestamp = System.currentTimeMillis() + (10 * 60 * 1000L)
|
expirationTimestamp = System.currentTimeMillis() + (10 * 60 * 1000L)
|
||||||
}
|
}
|
||||||
PopupAlertManager.postVectorAlert(alert)
|
popupAlertManager.postVectorAlert(alert)
|
||||||
}
|
}
|
||||||
is VerificationTxState.TerminalTxState -> {
|
is VerificationTxState.TerminalTxState -> {
|
||||||
// cancel related notification
|
// cancel related notification
|
||||||
PopupAlertManager.cancelAlert(uid)
|
popupAlertManager.cancelAlert(uid)
|
||||||
}
|
}
|
||||||
else -> Unit
|
else -> Unit
|
||||||
}
|
}
|
||||||
@ -115,7 +122,7 @@ class IncomingVerificationRequestHandler @Inject constructor(private val context
|
|||||||
val name = session?.getUser(pr.otherUserId)?.displayName
|
val name = session?.getUser(pr.otherUserId)?.displayName
|
||||||
?: pr.otherUserId
|
?: pr.otherUserId
|
||||||
|
|
||||||
val alert = PopupAlertManager.VectorAlert(
|
val alert = VerificationVectorAlert(
|
||||||
uniqueIdForVerificationRequest(pr),
|
uniqueIdForVerificationRequest(pr),
|
||||||
context.getString(R.string.sas_incoming_request_notif_title),
|
context.getString(R.string.sas_incoming_request_notif_title),
|
||||||
"$name(${pr.otherUserId})",
|
"$name(${pr.otherUserId})",
|
||||||
@ -128,6 +135,9 @@ class IncomingVerificationRequestHandler @Inject constructor(private val context
|
|||||||
} else true
|
} else true
|
||||||
})
|
})
|
||||||
.apply {
|
.apply {
|
||||||
|
|
||||||
|
matrixItem = session?.getUser(pr.otherUserId)?.toMatrixItem()
|
||||||
|
|
||||||
contentAction = Runnable {
|
contentAction = Runnable {
|
||||||
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
|
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
|
||||||
val roomId = pr.roomId
|
val roomId = pr.roomId
|
||||||
@ -148,14 +158,14 @@ class IncomingVerificationRequestHandler @Inject constructor(private val context
|
|||||||
// 5mn expiration
|
// 5mn expiration
|
||||||
expirationTimestamp = System.currentTimeMillis() + (5 * 60 * 1000L)
|
expirationTimestamp = System.currentTimeMillis() + (5 * 60 * 1000L)
|
||||||
}
|
}
|
||||||
PopupAlertManager.postVectorAlert(alert)
|
popupAlertManager.postVectorAlert(alert)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun verificationRequestUpdated(pr: PendingVerificationRequest) {
|
override fun verificationRequestUpdated(pr: PendingVerificationRequest) {
|
||||||
// If an incoming request is readied (by another device?) we should discard the alert
|
// If an incoming request is readied (by another device?) we should discard the alert
|
||||||
if (pr.isIncoming && (pr.isReady || pr.handledByOtherSession)) {
|
if (pr.isIncoming && (pr.isReady || pr.handledByOtherSession)) {
|
||||||
PopupAlertManager.cancelAlert(uniqueIdForVerificationRequest(pr))
|
popupAlertManager.cancelAlert(uniqueIdForVerificationRequest(pr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,8 @@ import im.vector.riotx.core.pushers.PushersManager
|
|||||||
import im.vector.riotx.features.disclaimer.showDisclaimerDialog
|
import im.vector.riotx.features.disclaimer.showDisclaimerDialog
|
||||||
import im.vector.riotx.features.notifications.NotificationDrawerManager
|
import im.vector.riotx.features.notifications.NotificationDrawerManager
|
||||||
import im.vector.riotx.features.popup.PopupAlertManager
|
import im.vector.riotx.features.popup.PopupAlertManager
|
||||||
|
import im.vector.riotx.features.popup.VectorAlert
|
||||||
|
import im.vector.riotx.features.popup.VerificationVectorAlert
|
||||||
import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler
|
import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler
|
||||||
import im.vector.riotx.features.settings.VectorPreferences
|
import im.vector.riotx.features.settings.VectorPreferences
|
||||||
import im.vector.riotx.features.workers.signout.SignOutViewModel
|
import im.vector.riotx.features.workers.signout.SignOutViewModel
|
||||||
@ -60,6 +62,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
|
|||||||
@Inject lateinit var pushManager: PushersManager
|
@Inject lateinit var pushManager: PushersManager
|
||||||
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager
|
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager
|
||||||
@Inject lateinit var vectorPreferences: VectorPreferences
|
@Inject lateinit var vectorPreferences: VectorPreferences
|
||||||
|
@Inject lateinit var popupAlertManager: PopupAlertManager
|
||||||
|
|
||||||
private val drawerListener = object : DrawerLayout.SimpleDrawerListener() {
|
private val drawerListener = object : DrawerLayout.SimpleDrawerListener() {
|
||||||
override fun onDrawerStateChanged(newState: Int) {
|
override fun onDrawerStateChanged(newState: Int) {
|
||||||
@ -149,8 +152,8 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
|
|||||||
if (crossSigningEnabledOnAccount && myCrossSigningKeys?.isTrusted() == false) {
|
if (crossSigningEnabledOnAccount && myCrossSigningKeys?.isTrusted() == false) {
|
||||||
// We need to ask
|
// We need to ask
|
||||||
sharedActionViewModel.hasDisplayedCompleteSecurityPrompt = true
|
sharedActionViewModel.hasDisplayedCompleteSecurityPrompt = true
|
||||||
PopupAlertManager.postVectorAlert(
|
popupAlertManager.postVectorAlert(
|
||||||
PopupAlertManager.VectorAlert(
|
VerificationVectorAlert(
|
||||||
uid = "completeSecurity",
|
uid = "completeSecurity",
|
||||||
title = getString(R.string.new_signin),
|
title = getString(R.string.new_signin),
|
||||||
description = getString(R.string.complete_security),
|
description = getString(R.string.complete_security),
|
||||||
|
@ -42,6 +42,7 @@ import im.vector.riotx.features.home.room.list.RoomListFragment
|
|||||||
import im.vector.riotx.features.home.room.list.RoomListParams
|
import im.vector.riotx.features.home.room.list.RoomListParams
|
||||||
import im.vector.riotx.features.home.room.list.UnreadCounterBadgeView
|
import im.vector.riotx.features.home.room.list.UnreadCounterBadgeView
|
||||||
import im.vector.riotx.features.popup.PopupAlertManager
|
import im.vector.riotx.features.popup.PopupAlertManager
|
||||||
|
import im.vector.riotx.features.popup.VectorAlert
|
||||||
import im.vector.riotx.features.workers.signout.SignOutViewModel
|
import im.vector.riotx.features.workers.signout.SignOutViewModel
|
||||||
import kotlinx.android.synthetic.main.fragment_home_detail.*
|
import kotlinx.android.synthetic.main.fragment_home_detail.*
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@ -53,7 +54,8 @@ private const val INDEX_ROOMS = 2
|
|||||||
|
|
||||||
class HomeDetailFragment @Inject constructor(
|
class HomeDetailFragment @Inject constructor(
|
||||||
val homeDetailViewModelFactory: HomeDetailViewModel.Factory,
|
val homeDetailViewModelFactory: HomeDetailViewModel.Factory,
|
||||||
private val avatarRenderer: AvatarRenderer
|
private val avatarRenderer: AvatarRenderer,
|
||||||
|
private val alertManager: PopupAlertManager
|
||||||
) : VectorBaseFragment(), KeysBackupBanner.Delegate {
|
) : VectorBaseFragment(), KeysBackupBanner.Delegate {
|
||||||
|
|
||||||
private val unreadCounterBadgeViews = arrayListOf<UnreadCounterBadgeView>()
|
private val unreadCounterBadgeViews = arrayListOf<UnreadCounterBadgeView>()
|
||||||
@ -89,19 +91,21 @@ class HomeDetailFragment @Inject constructor(
|
|||||||
it.unknownSessions.invoke()?.let { unknownDevices ->
|
it.unknownSessions.invoke()?.let { unknownDevices ->
|
||||||
Timber.v("## Detector - ${unknownDevices.size} Unknown sessions")
|
Timber.v("## Detector - ${unknownDevices.size} Unknown sessions")
|
||||||
unknownDevices.forEachIndexed { index, deviceInfo ->
|
unknownDevices.forEachIndexed { index, deviceInfo ->
|
||||||
Timber.v("## Detector - #${index} deviceId:${deviceInfo.deviceId} lastSeenTs:${deviceInfo.lastSeenTs}")
|
Timber.v("## Detector - #${index} deviceId:${deviceInfo.second.deviceId} lastSeenTs:${deviceInfo.second.lastSeenTs}")
|
||||||
}
|
}
|
||||||
if (it.canCrossSign && unknownDevices.isNotEmpty()) {
|
if (it.canCrossSign && unknownDevices.isNotEmpty()) {
|
||||||
val newest = unknownDevices.first()
|
val newest = unknownDevices.first().second
|
||||||
|
val user = unknownDevices.first().first
|
||||||
val uid = "ND_${newest.deviceId}"
|
val uid = "ND_${newest.deviceId}"
|
||||||
PopupAlertManager.cancelAlert(uid)
|
alertManager.cancelAlert(uid)
|
||||||
PopupAlertManager.postVectorAlert(
|
alertManager.postVectorAlert(
|
||||||
PopupAlertManager.VectorAlert(
|
VectorAlert(
|
||||||
uid = uid,
|
uid = uid,
|
||||||
title = getString(R.string.new_session),
|
title = getString(R.string.new_session),
|
||||||
description = getString(R.string.new_session_review),
|
description = getString(R.string.new_session_review),
|
||||||
iconId = R.drawable.ic_shield_warning
|
iconId = R.drawable.ic_shield_warning
|
||||||
).apply {
|
).apply {
|
||||||
|
matrixItem = user
|
||||||
colorInt = ContextCompat.getColor(requireActivity(), R.color.riotx_accent)
|
colorInt = ContextCompat.getColor(requireActivity(), R.color.riotx_accent)
|
||||||
contentAction = Runnable {
|
contentAction = Runnable {
|
||||||
(weakCurrentActivity?.get() as? VectorBaseActivity)
|
(weakCurrentActivity?.get() as? VectorBaseActivity)
|
||||||
|
@ -22,7 +22,9 @@ import com.airbnb.mvrx.MvRxViewModelFactory
|
|||||||
import com.airbnb.mvrx.Uninitialized
|
import com.airbnb.mvrx.Uninitialized
|
||||||
import com.airbnb.mvrx.ViewModelContext
|
import com.airbnb.mvrx.ViewModelContext
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.matrix.android.api.session.Session
|
||||||
|
import im.vector.matrix.android.api.util.MatrixItem
|
||||||
import im.vector.matrix.android.api.util.NoOpCancellable
|
import im.vector.matrix.android.api.util.NoOpCancellable
|
||||||
|
import im.vector.matrix.android.api.util.toMatrixItem
|
||||||
import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
|
import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
|
||||||
import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse
|
import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse
|
||||||
import im.vector.matrix.rx.rx
|
import im.vector.matrix.rx.rx
|
||||||
@ -34,7 +36,8 @@ import im.vector.riotx.core.platform.VectorViewModel
|
|||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
|
|
||||||
data class UnknownDevicesState(
|
data class UnknownDevicesState(
|
||||||
val unknownSessions: Async<List<DeviceInfo>?> = Uninitialized,
|
val unknownSessions: Async<List<Pair<MatrixItem?,DeviceInfo>>?> = Uninitialized,
|
||||||
|
val verifiedSessions: Async<List<Pair<MatrixItem?,DeviceInfo>>?> = Uninitialized,
|
||||||
val canCrossSign: Boolean = false
|
val canCrossSign: Boolean = false
|
||||||
) : MvRxState
|
) : MvRxState
|
||||||
|
|
||||||
@ -51,6 +54,9 @@ class UnknownDeviceDetectorSharedViewModel(session: Session, initialState: Unkno
|
|||||||
resp.devices?.filter { info ->
|
resp.devices?.filter { info ->
|
||||||
deviceList.firstOrNull { info.deviceId == it.deviceId }?.isVerified?.not() ?: false
|
deviceList.firstOrNull { info.deviceId == it.deviceId }?.isVerified?.not() ?: false
|
||||||
}?.sortedByDescending { it.lastSeenTs }
|
}?.sortedByDescending { it.lastSeenTs }
|
||||||
|
?.map {
|
||||||
|
session.getUser(it.user_id ?: "")?.toMatrixItem() to it
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.toObservable()
|
.toObservable()
|
||||||
}
|
}
|
||||||
|
@ -22,12 +22,12 @@ import android.os.Bundle
|
|||||||
import im.vector.riotx.features.popup.PopupAlertManager
|
import im.vector.riotx.features.popup.PopupAlertManager
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class VectorActivityLifecycleCallbacks @Inject constructor() : Application.ActivityLifecycleCallbacks {
|
class VectorActivityLifecycleCallbacks constructor(private val popupAlertManager: PopupAlertManager) : Application.ActivityLifecycleCallbacks {
|
||||||
override fun onActivityPaused(activity: Activity) {
|
override fun onActivityPaused(activity: Activity) {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityResumed(activity: Activity) {
|
override fun onActivityResumed(activity: Activity) {
|
||||||
PopupAlertManager.onNewActivityDisplayed(activity)
|
popupAlertManager.onNewActivityDisplayed(activity)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityStarted(activity: Activity) {
|
override fun onActivityStarted(activity: Activity) {
|
||||||
|
@ -20,20 +20,23 @@ import android.os.Build
|
|||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.annotation.ColorInt
|
import android.widget.ImageView
|
||||||
import androidx.annotation.ColorRes
|
|
||||||
import androidx.annotation.DrawableRes
|
|
||||||
import com.tapadoo.alerter.Alerter
|
import com.tapadoo.alerter.Alerter
|
||||||
import com.tapadoo.alerter.OnHideAlertListener
|
import com.tapadoo.alerter.OnHideAlertListener
|
||||||
|
import dagger.Lazy
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
|
import im.vector.riotx.features.home.AvatarRenderer
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Responsible of displaying important popup alerts on top of the screen.
|
* Responsible of displaying important popup alerts on top of the screen.
|
||||||
* Alerts are stacked and will be displayed sequentially
|
* Alerts are stacked and will be displayed sequentially
|
||||||
*/
|
*/
|
||||||
object PopupAlertManager {
|
@Singleton
|
||||||
|
class PopupAlertManager @Inject constructor(private val avatarRenderer: Lazy<AvatarRenderer>) {
|
||||||
|
|
||||||
private var weakCurrentActivity: WeakReference<Activity>? = null
|
private var weakCurrentActivity: WeakReference<Activity>? = null
|
||||||
private var currentAlerter: VectorAlert? = null
|
private var currentAlerter: VectorAlert? = null
|
||||||
@ -160,9 +163,19 @@ object PopupAlertManager {
|
|||||||
clearLightStatusBar()
|
clearLightStatusBar()
|
||||||
|
|
||||||
alert.weakCurrentActivity = WeakReference(activity)
|
alert.weakCurrentActivity = WeakReference(activity)
|
||||||
Alerter.create(activity)
|
val alerter = if (alert is VerificationVectorAlert) Alerter.create(activity, R.layout.alerter_verification_layout)
|
||||||
.setTitle(alert.title)
|
else Alerter.create(activity)
|
||||||
|
|
||||||
|
alerter.setTitle(alert.title)
|
||||||
.setText(alert.description)
|
.setText(alert.description)
|
||||||
|
.also { al ->
|
||||||
|
if (alert is VerificationVectorAlert) {
|
||||||
|
val tvCustomView = al.getLayoutContainer()
|
||||||
|
tvCustomView?.findViewById<ImageView>(R.id.ivUserAvatar)?.let { imageView ->
|
||||||
|
alert.matrixItem?.let { avatarRenderer.get().render(it, imageView) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.apply {
|
.apply {
|
||||||
if (!animate) {
|
if (!animate) {
|
||||||
setEnterAnimation(R.anim.anim_alerter_no_anim)
|
setEnterAnimation(R.anim.anim_alerter_no_anim)
|
||||||
@ -226,37 +239,4 @@ object PopupAlertManager {
|
|||||||
displayNextIfPossible()
|
displayNextIfPossible()
|
||||||
}, 500)
|
}, 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Dataclass to describe an important alert with actions.
|
|
||||||
*/
|
|
||||||
data class VectorAlert(val uid: String,
|
|
||||||
val title: String,
|
|
||||||
val description: String,
|
|
||||||
@DrawableRes val iconId: Int?,
|
|
||||||
val shouldBeDisplayedIn: ((Activity) -> Boolean)? = null) {
|
|
||||||
|
|
||||||
data class Button(val title: String, val action: Runnable, val autoClose: Boolean)
|
|
||||||
|
|
||||||
// will be set by manager, and accessible by actions at runtime
|
|
||||||
var weakCurrentActivity: WeakReference<Activity>? = null
|
|
||||||
|
|
||||||
val actions = ArrayList<Button>()
|
|
||||||
|
|
||||||
var contentAction: Runnable? = null
|
|
||||||
var dismissedAction: Runnable? = null
|
|
||||||
|
|
||||||
/** If this timestamp is after current time, this alert will be skipped */
|
|
||||||
var expirationTimestamp: Long? = null
|
|
||||||
|
|
||||||
fun addButton(title: String, action: Runnable, autoClose: Boolean = true) {
|
|
||||||
actions.add(Button(title, action, autoClose))
|
|
||||||
}
|
|
||||||
|
|
||||||
@ColorRes
|
|
||||||
var colorRes: Int? = null
|
|
||||||
|
|
||||||
@ColorInt
|
|
||||||
var colorInt: Int? = null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* 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.riotx.features.popup
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
|
import androidx.annotation.ColorRes
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import im.vector.matrix.android.api.util.MatrixItem
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
|
|
||||||
|
interface VectorAlert {
|
||||||
|
val uid: String
|
||||||
|
val title: String
|
||||||
|
val description: String
|
||||||
|
val iconId: Int?
|
||||||
|
val shouldBeDisplayedIn: ((Activity) -> Boolean)?
|
||||||
|
|
||||||
|
data class Button(val title: String, val action: Runnable, val autoClose: Boolean)
|
||||||
|
|
||||||
|
// will be set by manager, and accessible by actions at runtime
|
||||||
|
var weakCurrentActivity: WeakReference<Activity>?
|
||||||
|
|
||||||
|
val actions: MutableList<Button>
|
||||||
|
|
||||||
|
var contentAction: Runnable?
|
||||||
|
var dismissedAction: Runnable?
|
||||||
|
|
||||||
|
/** If this timestamp is after current time, this alert will be skipped */
|
||||||
|
var expirationTimestamp: Long?
|
||||||
|
|
||||||
|
fun addButton(title: String, action: Runnable, autoClose: Boolean = true) {
|
||||||
|
actions.add(Button(title, action, autoClose))
|
||||||
|
}
|
||||||
|
|
||||||
|
var colorRes: Int?
|
||||||
|
|
||||||
|
var colorInt: Int?
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dataclass to describe an important alert with actions.
|
||||||
|
*/
|
||||||
|
open class DefaultVectorAlert(override val uid: String,
|
||||||
|
override val title: String,
|
||||||
|
override val description: String,
|
||||||
|
@DrawableRes override val iconId: Int?,
|
||||||
|
override val shouldBeDisplayedIn: ((Activity) -> Boolean)? = null) : VectorAlert {
|
||||||
|
|
||||||
|
// will be set by manager, and accessible by actions at runtime
|
||||||
|
override var weakCurrentActivity: WeakReference<Activity>? = null
|
||||||
|
|
||||||
|
override val actions = ArrayList<VectorAlert.Button>()
|
||||||
|
|
||||||
|
override var contentAction: Runnable? = null
|
||||||
|
override var dismissedAction: Runnable? = null
|
||||||
|
|
||||||
|
/** If this timestamp is after current time, this alert will be skipped */
|
||||||
|
override var expirationTimestamp: Long? = null
|
||||||
|
|
||||||
|
override fun addButton(title: String, action: Runnable, autoClose: Boolean) {
|
||||||
|
actions.add(VectorAlert.Button(title, action, autoClose))
|
||||||
|
}
|
||||||
|
|
||||||
|
@ColorRes
|
||||||
|
override var colorRes: Int? = null
|
||||||
|
|
||||||
|
@ColorInt
|
||||||
|
override var colorInt: Int? = null
|
||||||
|
}
|
||||||
|
|
||||||
|
class VerificationVectorAlert(uid: String,
|
||||||
|
title: String,
|
||||||
|
override val description: String,
|
||||||
|
@DrawableRes override val iconId: Int?,
|
||||||
|
override val shouldBeDisplayedIn: ((Activity) -> Boolean)? = null
|
||||||
|
) : DefaultVectorAlert(
|
||||||
|
uid, title, description, iconId, shouldBeDisplayedIn
|
||||||
|
) {
|
||||||
|
var matrixItem: MatrixItem? = null
|
||||||
|
}
|
92
vector/src/main/res/layout/alerter_verification_layout.xml
Normal file
92
vector/src/main/res/layout/alerter_verification_layout.xml
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
tools:background="@android:color/darker_gray"
|
||||||
|
tools:foreground="?android:attr/selectableItemBackground"
|
||||||
|
tools:style="@style/AlertStyle">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/ivUserAvatar"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/alerter_texts"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:src="@tools:sample/avatars" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/ivIcon"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
app:layout_constraintCircle="@+id/ivUserAvatar"
|
||||||
|
app:layout_constraintCircleAngle="135"
|
||||||
|
app:layout_constraintCircleRadius="20dp"
|
||||||
|
tools:ignore="MissingConstraints"
|
||||||
|
android:src="@drawable/ic_shield_warning"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/alerter_texts"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/ivUserAvatar"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
|
android:id="@+id/tvTitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/alerter_padding_half"
|
||||||
|
android:layout_marginEnd="@dimen/alerter_padding_half"
|
||||||
|
android:paddingStart="@dimen/alerter_padding_small"
|
||||||
|
android:paddingLeft="@dimen/alerter_padding_small"
|
||||||
|
android:paddingEnd="@dimen/alerter_padding_small"
|
||||||
|
android:textAppearance="@style/AlertTextAppearance.Title"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:text="Title"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
|
android:id="@+id/tvText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/alerter_padding_half"
|
||||||
|
android:layout_marginEnd="@dimen/alerter_padding_half"
|
||||||
|
android:paddingStart="@dimen/alerter_padding_small"
|
||||||
|
android:paddingLeft="@dimen/alerter_padding_small"
|
||||||
|
android:paddingTop="@dimen/alerter_padding_small"
|
||||||
|
android:paddingEnd="@dimen/alerter_padding_small"
|
||||||
|
android:paddingBottom="@dimen/alerter_padding_small"
|
||||||
|
android:textAppearance="@style/AlertTextAppearance.Text"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:text="Text"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- <FrameLayout-->
|
||||||
|
<!-- android:id="@+id/flRightIconContainer"-->
|
||||||
|
<!-- android:layout_width="wrap_content"-->
|
||||||
|
<!-- android:layout_height="wrap_content"-->
|
||||||
|
<!-- android:layout_gravity="center_vertical">-->
|
||||||
|
|
||||||
|
<!-- <androidx.appcompat.widget.AppCompatImageView-->
|
||||||
|
<!-- android:id="@+id/ivRightIcon"-->
|
||||||
|
<!-- android:layout_width="@dimen/alerter_alert_icn_size"-->
|
||||||
|
<!-- android:layout_height="@dimen/alerter_alert_icn_size"-->
|
||||||
|
<!-- android:maxWidth="@dimen/alerter_alert_icn_size"-->
|
||||||
|
<!-- android:maxHeight="@dimen/alerter_alert_icn_size"-->
|
||||||
|
<!-- android:visibility="gone"-->
|
||||||
|
<!-- app:srcCompat="@drawable/alerter_ic_notifications"-->
|
||||||
|
<!-- app:tint="@color/alert_default_icon_color"-->
|
||||||
|
<!-- tools:visibility="visible" />-->
|
||||||
|
<!-- </FrameLayout>-->
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
Loading…
x
Reference in New Issue
Block a user