mirror of
https://github.com/element-hq/element-android
synced 2024-11-24 02:15:35 +03:00
Merge pull request #4734 from vector-im/feature/bma/analytics_next
Implement analytics plan
This commit is contained in:
commit
9bfeb6f814
59 changed files with 882 additions and 151 deletions
1
changelog.d/4734.misc
Normal file
1
changelog.d/4734.misc
Normal file
|
@ -0,0 +1 @@
|
|||
Analytics: send more Events
|
|
@ -160,7 +160,7 @@ Formatter\.formatShortFileSize===1
|
|||
# android\.text\.TextUtils
|
||||
|
||||
### This is not a rule, but a warning: the number of "enum class" has changed. For Json classes, it is mandatory that they have `@JsonClass(generateAdapter = false)`. If the enum is not used as a Json class, change the value in file forbidden_strings_in_code.txt
|
||||
enum class===119
|
||||
enum class===121
|
||||
|
||||
### Do not import temporary legacy classes
|
||||
import org.matrix.android.sdk.internal.legacy.riot===3
|
||||
|
|
|
@ -21,7 +21,7 @@ import dagger.hilt.InstallIn
|
|||
import dagger.hilt.components.SingletonComponent
|
||||
import im.vector.app.core.dialogs.UnrecognizedCertificateDialog
|
||||
import im.vector.app.core.error.ErrorFormatter
|
||||
import im.vector.app.features.analytics.VectorAnalytics
|
||||
import im.vector.app.features.analytics.AnalyticsTracker
|
||||
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.navigation.Navigator
|
||||
|
@ -56,7 +56,7 @@ interface SingletonEntryPoint {
|
|||
|
||||
fun pinLocker(): PinLocker
|
||||
|
||||
fun analytics(): VectorAnalytics
|
||||
fun analyticsTracker(): AnalyticsTracker
|
||||
|
||||
fun webRtcCallManager(): WebRtcCallManager
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ import im.vector.app.core.error.DefaultErrorFormatter
|
|||
import im.vector.app.core.error.ErrorFormatter
|
||||
import im.vector.app.core.time.Clock
|
||||
import im.vector.app.core.time.DefaultClock
|
||||
import im.vector.app.features.analytics.AnalyticsTracker
|
||||
import im.vector.app.features.analytics.VectorAnalytics
|
||||
import im.vector.app.features.analytics.impl.DefaultVectorAnalytics
|
||||
import im.vector.app.features.invite.AutoAcceptInvites
|
||||
|
@ -64,6 +65,9 @@ abstract class VectorBindModule {
|
|||
@Binds
|
||||
abstract fun bindVectorAnalytics(analytics: DefaultVectorAnalytics): VectorAnalytics
|
||||
|
||||
@Binds
|
||||
abstract fun bindAnalyticsTracker(analytics: DefaultVectorAnalytics): AnalyticsTracker
|
||||
|
||||
@Binds
|
||||
abstract fun bindErrorFormatter(formatter: DefaultErrorFormatter): ErrorFormatter
|
||||
|
||||
|
|
|
@ -65,7 +65,9 @@ import im.vector.app.core.extensions.toMvRxBundle
|
|||
import im.vector.app.core.utils.toast
|
||||
import im.vector.app.features.MainActivity
|
||||
import im.vector.app.features.MainActivityArgs
|
||||
import im.vector.app.features.analytics.VectorAnalytics
|
||||
import im.vector.app.features.analytics.AnalyticsTracker
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import im.vector.app.features.analytics.screen.ScreenEvent
|
||||
import im.vector.app.features.configuration.VectorConfiguration
|
||||
import im.vector.app.features.consent.ConsentNotGivenHelper
|
||||
import im.vector.app.features.navigation.Navigator
|
||||
|
@ -90,6 +92,15 @@ import timber.log.Timber
|
|||
import javax.inject.Inject
|
||||
|
||||
abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), MavericksView {
|
||||
/* ==========================================================================================
|
||||
* Analytics
|
||||
* ========================================================================================== */
|
||||
|
||||
protected var analyticsScreenName: Screen.ScreenName? = null
|
||||
private var screenEvent: ScreenEvent? = null
|
||||
|
||||
protected lateinit var analyticsTracker: AnalyticsTracker
|
||||
|
||||
/* ==========================================================================================
|
||||
* View
|
||||
* ========================================================================================== */
|
||||
|
@ -133,7 +144,6 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
|
|||
private lateinit var sessionListener: SessionListener
|
||||
protected lateinit var bugReporter: BugReporter
|
||||
private lateinit var pinLocker: PinLocker
|
||||
protected lateinit var analytics: VectorAnalytics
|
||||
|
||||
@Inject
|
||||
lateinit var rageShake: RageShake
|
||||
|
@ -189,7 +199,7 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
|
|||
configurationViewModel = viewModelProvider.get(ConfigurationViewModel::class.java)
|
||||
bugReporter = singletonEntryPoint.bugReporter()
|
||||
pinLocker = singletonEntryPoint.pinLocker()
|
||||
analytics = singletonEntryPoint.analytics()
|
||||
analyticsTracker = singletonEntryPoint.analyticsTracker()
|
||||
navigator = singletonEntryPoint.navigator()
|
||||
activeSessionHolder = singletonEntryPoint.activeSessionHolder()
|
||||
vectorPreferences = singletonEntryPoint.vectorPreferences()
|
||||
|
@ -324,7 +334,7 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
|
|||
override fun onResume() {
|
||||
super.onResume()
|
||||
Timber.i("onResume Activity ${javaClass.simpleName}")
|
||||
|
||||
screenEvent = analyticsScreenName?.let { ScreenEvent(it) }
|
||||
configurationViewModel.onActivityResumed()
|
||||
|
||||
if (this !is BugReportActivity && vectorPreferences.useRageshake()) {
|
||||
|
@ -363,6 +373,7 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
|
|||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
screenEvent?.send(analyticsTracker, analyticsScreenName)
|
||||
Timber.i("onPause Activity ${javaClass.simpleName}")
|
||||
|
||||
rageShake.stop()
|
||||
|
|
|
@ -37,7 +37,9 @@ import im.vector.app.core.di.ActivityEntryPoint
|
|||
import im.vector.app.core.extensions.singletonEntryPoint
|
||||
import im.vector.app.core.extensions.toMvRxBundle
|
||||
import im.vector.app.core.utils.DimensionConverter
|
||||
import im.vector.app.features.analytics.VectorAnalytics
|
||||
import im.vector.app.features.analytics.AnalyticsTracker
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import im.vector.app.features.analytics.screen.ScreenEvent
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import reactivecircus.flowbinding.android.view.clicks
|
||||
|
@ -47,6 +49,14 @@ import timber.log.Timber
|
|||
* Add Mavericks capabilities, handle DI and bindings.
|
||||
*/
|
||||
abstract class VectorBaseBottomSheetDialogFragment<VB : ViewBinding> : BottomSheetDialogFragment(), MavericksView {
|
||||
/* ==========================================================================================
|
||||
* Analytics
|
||||
* ========================================================================================== */
|
||||
|
||||
protected var analyticsScreenName: Screen.ScreenName? = null
|
||||
private var screenEvent: ScreenEvent? = null
|
||||
|
||||
protected lateinit var analyticsTracker: AnalyticsTracker
|
||||
|
||||
/* ==========================================================================================
|
||||
* View
|
||||
|
@ -84,8 +94,6 @@ abstract class VectorBaseBottomSheetDialogFragment<VB : ViewBinding> : BottomShe
|
|||
|
||||
open val showExpanded = false
|
||||
|
||||
protected lateinit var analytics: VectorAnalytics
|
||||
|
||||
interface ResultListener {
|
||||
fun onBottomSheetResult(resultCode: Int, data: Any?)
|
||||
|
||||
|
@ -124,13 +132,19 @@ abstract class VectorBaseBottomSheetDialogFragment<VB : ViewBinding> : BottomShe
|
|||
val activityEntryPoint = EntryPointAccessors.fromActivity(vectorBaseActivity, ActivityEntryPoint::class.java)
|
||||
viewModelFactory = activityEntryPoint.viewModelFactory()
|
||||
val singletonEntryPoint = context.singletonEntryPoint()
|
||||
analytics = singletonEntryPoint.analytics()
|
||||
analyticsTracker = singletonEntryPoint.analyticsTracker()
|
||||
super.onAttach(context)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
Timber.i("onResume BottomSheet ${javaClass.simpleName}")
|
||||
screenEvent = analyticsScreenName?.let { ScreenEvent(it) }
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
screenEvent?.send(analyticsTracker)
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
|
|
|
@ -42,7 +42,9 @@ import im.vector.app.core.dialogs.UnrecognizedCertificateDialog
|
|||
import im.vector.app.core.error.ErrorFormatter
|
||||
import im.vector.app.core.extensions.singletonEntryPoint
|
||||
import im.vector.app.core.extensions.toMvRxBundle
|
||||
import im.vector.app.features.analytics.VectorAnalytics
|
||||
import im.vector.app.features.analytics.AnalyticsTracker
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import im.vector.app.features.analytics.screen.ScreenEvent
|
||||
import im.vector.app.features.navigation.Navigator
|
||||
import im.vector.lib.ui.styles.dialogs.MaterialProgressDialog
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
|
@ -51,6 +53,18 @@ import reactivecircus.flowbinding.android.view.clicks
|
|||
import timber.log.Timber
|
||||
|
||||
abstract class VectorBaseFragment<VB : ViewBinding> : Fragment(), MavericksView {
|
||||
/* ==========================================================================================
|
||||
* Analytics
|
||||
* ========================================================================================== */
|
||||
|
||||
protected var analyticsScreenName: Screen.ScreenName? = null
|
||||
private var screenEvent: ScreenEvent? = null
|
||||
|
||||
protected lateinit var analyticsTracker: AnalyticsTracker
|
||||
|
||||
/* ==========================================================================================
|
||||
* Activity
|
||||
* ========================================================================================== */
|
||||
|
||||
protected val vectorBaseActivity: VectorBaseActivity<*> by lazy {
|
||||
activity as VectorBaseActivity<*>
|
||||
|
@ -61,7 +75,6 @@ abstract class VectorBaseFragment<VB : ViewBinding> : Fragment(), MavericksView
|
|||
* ========================================================================================== */
|
||||
|
||||
protected lateinit var navigator: Navigator
|
||||
protected lateinit var analytics: VectorAnalytics
|
||||
protected lateinit var errorFormatter: ErrorFormatter
|
||||
protected lateinit var unrecognizedCertificateDialog: UnrecognizedCertificateDialog
|
||||
|
||||
|
@ -98,7 +111,7 @@ abstract class VectorBaseFragment<VB : ViewBinding> : Fragment(), MavericksView
|
|||
val activityEntryPoint = EntryPointAccessors.fromActivity(vectorBaseActivity, ActivityEntryPoint::class.java)
|
||||
navigator = singletonEntryPoint.navigator()
|
||||
errorFormatter = singletonEntryPoint.errorFormatter()
|
||||
analytics = singletonEntryPoint.analytics()
|
||||
analyticsTracker = singletonEntryPoint.analyticsTracker()
|
||||
unrecognizedCertificateDialog = singletonEntryPoint.unrecognizedCertificateDialog()
|
||||
viewModelFactory = activityEntryPoint.viewModelFactory()
|
||||
childFragmentManager.fragmentFactory = activityEntryPoint.fragmentFactory()
|
||||
|
@ -125,12 +138,14 @@ abstract class VectorBaseFragment<VB : ViewBinding> : Fragment(), MavericksView
|
|||
override fun onResume() {
|
||||
super.onResume()
|
||||
Timber.i("onResume Fragment ${javaClass.simpleName}")
|
||||
screenEvent = analyticsScreenName?.let { ScreenEvent(it) }
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
Timber.i("onPause Fragment ${javaClass.simpleName}")
|
||||
screenEvent?.send(analyticsTracker)
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.analytics
|
||||
|
||||
import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
|
||||
import im.vector.app.features.analytics.itf.VectorAnalyticsScreen
|
||||
|
||||
interface AnalyticsTracker {
|
||||
/**
|
||||
* Capture an Event
|
||||
*/
|
||||
fun capture(event: VectorAnalyticsEvent)
|
||||
|
||||
/**
|
||||
* Track a displayed screen
|
||||
*/
|
||||
fun screen(screen: VectorAnalyticsScreen)
|
||||
}
|
|
@ -49,7 +49,7 @@ private const val CHECK_INTERVAL = 2_000L
|
|||
*/
|
||||
@Singleton
|
||||
class DecryptionFailureTracker @Inject constructor(
|
||||
private val vectorAnalytics: VectorAnalytics,
|
||||
private val analyticsTracker: AnalyticsTracker,
|
||||
private val clock: Clock
|
||||
) {
|
||||
|
||||
|
@ -136,7 +136,7 @@ class DecryptionFailureTracker @Inject constructor(
|
|||
// for now we ignore events already reported even if displayed again?
|
||||
.filter { alreadyReported.contains(it).not() }
|
||||
.forEach { failedEventId ->
|
||||
vectorAnalytics.capture(Error(failedEventId, Error.Domain.E2EE, aggregation.key))
|
||||
analyticsTracker.capture(Error(failedEventId, Error.Domain.E2EE, aggregation.key))
|
||||
alreadyReported.add(failedEventId)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,11 +16,9 @@
|
|||
|
||||
package im.vector.app.features.analytics
|
||||
|
||||
import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
|
||||
import im.vector.app.features.analytics.itf.VectorAnalyticsScreen
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface VectorAnalytics {
|
||||
interface VectorAnalytics : AnalyticsTracker {
|
||||
/**
|
||||
* Return a Flow of Boolean, true if the user has given their consent
|
||||
*/
|
||||
|
@ -60,14 +58,4 @@ interface VectorAnalytics {
|
|||
* To be called when application is started
|
||||
*/
|
||||
fun init()
|
||||
|
||||
/**
|
||||
* Capture an Event
|
||||
*/
|
||||
fun capture(event: VectorAnalyticsEvent)
|
||||
|
||||
/**
|
||||
* Track a displayed screen
|
||||
*/
|
||||
fun screen(screen: VectorAnalyticsScreen)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.analytics.extensions
|
||||
|
||||
import im.vector.app.features.analytics.plan.JoinedRoom
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
|
||||
|
||||
fun Int?.toAnalyticsRoomSize(): JoinedRoom.RoomSize {
|
||||
return when (this) {
|
||||
null,
|
||||
2 -> JoinedRoom.RoomSize.Two
|
||||
in 3..10 -> JoinedRoom.RoomSize.ThreeToTen
|
||||
in 11..100 -> JoinedRoom.RoomSize.ElevenToOneHundred
|
||||
in 101..1000 -> JoinedRoom.RoomSize.OneHundredAndOneToAThousand
|
||||
else -> JoinedRoom.RoomSize.MoreThanAThousand
|
||||
}
|
||||
}
|
||||
|
||||
fun RoomSummary?.toAnalyticsJoinedRoom(): JoinedRoom {
|
||||
return JoinedRoom(
|
||||
isDM = this?.isDirect.orFalse(),
|
||||
roomSize = this?.joinedMembersCount?.toAnalyticsRoomSize() ?: JoinedRoom.RoomSize.Two
|
||||
)
|
||||
}
|
||||
|
||||
fun PublicRoom.toAnalyticsJoinedRoom(): JoinedRoom {
|
||||
return JoinedRoom(
|
||||
isDM = false,
|
||||
roomSize = numJoinedMembers.toAnalyticsRoomSize()
|
||||
)
|
||||
}
|
|
@ -25,22 +25,22 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
|
|||
* Triggered when a call has ended.
|
||||
*/
|
||||
data class CallEnded(
|
||||
/**
|
||||
* The duration of the call in milliseconds.
|
||||
*/
|
||||
val durationMs: Int,
|
||||
/**
|
||||
* Whether its a video call or not.
|
||||
*/
|
||||
val isVideo: Boolean,
|
||||
/**
|
||||
* Number of participants in the call.
|
||||
*/
|
||||
val numParticipants: Int,
|
||||
/**
|
||||
* Whether this user placed it.
|
||||
*/
|
||||
val placed: Boolean,
|
||||
/**
|
||||
* The duration of the call in milliseconds.
|
||||
*/
|
||||
val durationMs: Int,
|
||||
/**
|
||||
* Whether its a video call or not.
|
||||
*/
|
||||
val isVideo: Boolean,
|
||||
/**
|
||||
* Number of participants in the call.
|
||||
*/
|
||||
val numParticipants: Int,
|
||||
/**
|
||||
* Whether this user placed it.
|
||||
*/
|
||||
val placed: Boolean,
|
||||
) : VectorAnalyticsEvent {
|
||||
|
||||
override fun getName() = "CallEnded"
|
||||
|
|
|
@ -25,18 +25,18 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
|
|||
* Triggered when an error occurred in a call.
|
||||
*/
|
||||
data class CallError(
|
||||
/**
|
||||
* Whether its a video call or not.
|
||||
*/
|
||||
val isVideo: Boolean,
|
||||
/**
|
||||
* Number of participants in the call.
|
||||
*/
|
||||
val numParticipants: Int,
|
||||
/**
|
||||
* Whether this user placed it.
|
||||
*/
|
||||
val placed: Boolean,
|
||||
/**
|
||||
* Whether its a video call or not.
|
||||
*/
|
||||
val isVideo: Boolean,
|
||||
/**
|
||||
* Number of participants in the call.
|
||||
*/
|
||||
val numParticipants: Int,
|
||||
/**
|
||||
* Whether this user placed it.
|
||||
*/
|
||||
val placed: Boolean,
|
||||
) : VectorAnalyticsEvent {
|
||||
|
||||
override fun getName() = "CallError"
|
||||
|
|
|
@ -25,18 +25,18 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
|
|||
* Triggered when a call is started.
|
||||
*/
|
||||
data class CallStarted(
|
||||
/**
|
||||
* Whether its a video call or not.
|
||||
*/
|
||||
val isVideo: Boolean,
|
||||
/**
|
||||
* Number of participants in the call.
|
||||
*/
|
||||
val numParticipants: Int,
|
||||
/**
|
||||
* Whether this user placed it.
|
||||
*/
|
||||
val placed: Boolean,
|
||||
/**
|
||||
* Whether its a video call or not.
|
||||
*/
|
||||
val isVideo: Boolean,
|
||||
/**
|
||||
* Number of participants in the call.
|
||||
*/
|
||||
val numParticipants: Int,
|
||||
/**
|
||||
* Whether this user placed it.
|
||||
*/
|
||||
val placed: Boolean,
|
||||
) : VectorAnalyticsEvent {
|
||||
|
||||
override fun getName() = "CallStarted"
|
||||
|
|
|
@ -25,14 +25,14 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
|
|||
* Triggered when the user clicks/taps on a UI element.
|
||||
*/
|
||||
data class Click(
|
||||
/**
|
||||
* The index of the element, if its in a list of elements.
|
||||
*/
|
||||
val index: Int? = null,
|
||||
/**
|
||||
* The unique name of this element.
|
||||
*/
|
||||
val name: Name,
|
||||
/**
|
||||
* The index of the element, if its in a list of elements.
|
||||
*/
|
||||
val index: Int? = null,
|
||||
/**
|
||||
* The unique name of this element.
|
||||
*/
|
||||
val name: Name,
|
||||
) : VectorAnalyticsEvent {
|
||||
|
||||
enum class Name {
|
||||
|
|
|
@ -25,10 +25,10 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
|
|||
* Triggered when the user creates a room.
|
||||
*/
|
||||
data class CreatedRoom(
|
||||
/**
|
||||
* Whether the room is a DM.
|
||||
*/
|
||||
val isDM: Boolean,
|
||||
/**
|
||||
* Whether the room is a DM.
|
||||
*/
|
||||
val isDM: Boolean,
|
||||
) : VectorAnalyticsEvent {
|
||||
|
||||
override fun getName() = "CreatedRoom"
|
||||
|
|
|
@ -25,12 +25,12 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
|
|||
* Triggered when an error occurred
|
||||
*/
|
||||
data class Error(
|
||||
/**
|
||||
* Context - client defined, can be used for debugging
|
||||
*/
|
||||
val context: String? = null,
|
||||
val domain: Domain,
|
||||
val name: Name,
|
||||
/**
|
||||
* Context - client defined, can be used for debugging
|
||||
*/
|
||||
val context: String? = null,
|
||||
val domain: Domain,
|
||||
val name: Name,
|
||||
) : VectorAnalyticsEvent {
|
||||
|
||||
enum class Domain {
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.analytics.plan
|
||||
|
||||
import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
|
||||
|
||||
// GENERATED FILE, DO NOT EDIT. FOR MORE INFORMATION VISIT
|
||||
// https://github.com/matrix-org/matrix-analytics-events/
|
||||
|
||||
/**
|
||||
* The user properties to apply when identifying
|
||||
*/
|
||||
data class Identity(
|
||||
/**
|
||||
* The selected messaging use case during the onboarding flow.
|
||||
*/
|
||||
val ftueUseCaseSelection: FtueUseCaseSelection? = null,
|
||||
) : VectorAnalyticsEvent {
|
||||
|
||||
enum class FtueUseCaseSelection {
|
||||
/**
|
||||
* The third option, Communities.
|
||||
*/
|
||||
CommunityMessaging,
|
||||
|
||||
/**
|
||||
* The first option, Friends and family.
|
||||
*/
|
||||
PersonalMessaging,
|
||||
|
||||
/**
|
||||
* The footer option to skip the question.
|
||||
*/
|
||||
Skip,
|
||||
|
||||
/**
|
||||
* The second option, Teams.
|
||||
*/
|
||||
WorkMessaging,
|
||||
}
|
||||
|
||||
override fun getName() = "Identity"
|
||||
|
||||
override fun getProperties(): Map<String, Any>? {
|
||||
return mutableMapOf<String, Any>().apply {
|
||||
ftueUseCaseSelection?.let { put("ftueUseCaseSelection", it.name) }
|
||||
}.takeIf { it.isNotEmpty() }
|
||||
}
|
||||
}
|
|
@ -25,14 +25,14 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
|
|||
* Triggered when the user joins a room.
|
||||
*/
|
||||
data class JoinedRoom(
|
||||
/**
|
||||
* Whether the room is a DM.
|
||||
*/
|
||||
val isDM: Boolean,
|
||||
/**
|
||||
* The size of the room.
|
||||
*/
|
||||
val roomSize: RoomSize,
|
||||
/**
|
||||
* Whether the room is a DM.
|
||||
*/
|
||||
val isDM: Boolean,
|
||||
/**
|
||||
* The size of the room.
|
||||
*/
|
||||
val roomSize: RoomSize,
|
||||
) : VectorAnalyticsEvent {
|
||||
|
||||
enum class RoomSize {
|
||||
|
|
|
@ -25,22 +25,23 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
|
|||
* Triggered after timing an operation in the app.
|
||||
*/
|
||||
data class PerformanceTimer(
|
||||
/**
|
||||
* Client defined, can be used for debugging.
|
||||
*/
|
||||
val context: String? = null,
|
||||
/**
|
||||
* Client defined, an optional value to indicate how many items were handled during the operation.
|
||||
*/
|
||||
val itemCount: Int? = null,
|
||||
/**
|
||||
* The timer that is being reported.
|
||||
*/
|
||||
val name: Name,
|
||||
/**
|
||||
* The time reported by the timer in milliseconds.
|
||||
*/
|
||||
val timeMs: Int,
|
||||
/**
|
||||
* Client defined, can be used for debugging.
|
||||
*/
|
||||
val context: String? = null,
|
||||
/**
|
||||
* Client defined, an optional value to indicate how many items were
|
||||
* handled during the operation.
|
||||
*/
|
||||
val itemCount: Int? = null,
|
||||
/**
|
||||
* The timer that is being reported.
|
||||
*/
|
||||
val name: Name,
|
||||
/**
|
||||
* The time reported by the timer in milliseconds.
|
||||
*/
|
||||
val timeMs: Int,
|
||||
) : VectorAnalyticsEvent {
|
||||
|
||||
enum class Name {
|
||||
|
@ -55,7 +56,8 @@ data class PerformanceTimer(
|
|||
InitialSyncRequest,
|
||||
|
||||
/**
|
||||
* The time taken to display an event in the timeline that was opened from a notification.
|
||||
* The time taken to display an event in the timeline that was opened
|
||||
* from a notification.
|
||||
*/
|
||||
NotificationsOpenEvent,
|
||||
|
||||
|
@ -65,7 +67,8 @@ data class PerformanceTimer(
|
|||
StartupIncrementalSync,
|
||||
|
||||
/**
|
||||
* The duration of an initial /sync request during startup (if the store has been wiped).
|
||||
* The duration of an initial /sync request during startup (if the store
|
||||
* has been wiped).
|
||||
*/
|
||||
StartupInitialSync,
|
||||
|
||||
|
@ -80,7 +83,8 @@ data class PerformanceTimer(
|
|||
StartupStorePreload,
|
||||
|
||||
/**
|
||||
* The time to load all data from the store (including StartupStorePreload time).
|
||||
* The time to load all data from the store (including
|
||||
* StartupStorePreload time).
|
||||
*/
|
||||
StartupStoreReady,
|
||||
}
|
||||
|
|
|
@ -25,28 +25,221 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsScreen
|
|||
* Triggered when the user changed screen
|
||||
*/
|
||||
data class Screen(
|
||||
/**
|
||||
* How long the screen was displayed for in milliseconds.
|
||||
*/
|
||||
val durationMs: Int? = null,
|
||||
val screenName: ScreenName,
|
||||
/**
|
||||
* How long the screen was displayed for in milliseconds.
|
||||
*/
|
||||
val durationMs: Int? = null,
|
||||
val screenName: ScreenName,
|
||||
) : VectorAnalyticsScreen {
|
||||
|
||||
enum class ScreenName {
|
||||
/**
|
||||
* The screen shown to create a new (non-direct) room.
|
||||
*/
|
||||
CreateRoom,
|
||||
|
||||
/**
|
||||
* The confirmation screen shown before deactivating an account.
|
||||
*/
|
||||
DeactivateAccount,
|
||||
|
||||
/**
|
||||
* The form for the forgot password use case
|
||||
*/
|
||||
ForgotPassword,
|
||||
|
||||
/**
|
||||
* Legacy: The screen that shows information about a specific group.
|
||||
*/
|
||||
Group,
|
||||
|
||||
/**
|
||||
* The Home tab on iOS | possibly the same on Android? | The Home space
|
||||
* on Web?
|
||||
*/
|
||||
Home,
|
||||
|
||||
/**
|
||||
* The screen that displays the login flow (when the user already has an
|
||||
* account).
|
||||
*/
|
||||
Login,
|
||||
|
||||
/**
|
||||
* The screen that displays the user's breadcrumbs.
|
||||
*/
|
||||
MobileBreadcrumbs,
|
||||
|
||||
/**
|
||||
* The tab on mobile that displays the dialpad.
|
||||
*/
|
||||
MobileDialpad,
|
||||
|
||||
/**
|
||||
* The Favourites tab on mobile that lists your favourite people/rooms.
|
||||
*/
|
||||
MobileFavourites,
|
||||
|
||||
/**
|
||||
* The screen shown to share a link to download the app.
|
||||
*/
|
||||
MobileInviteFriends,
|
||||
|
||||
/**
|
||||
* The People tab on mobile that lists all the DM rooms you have joined.
|
||||
*/
|
||||
MobilePeople,
|
||||
|
||||
/**
|
||||
* The Rooms tab on mobile that lists all the (non-direct) rooms you've
|
||||
* joined.
|
||||
*/
|
||||
MobileRooms,
|
||||
|
||||
/**
|
||||
* The Files tab shown in the global search screen on Mobile.
|
||||
*/
|
||||
MobileSearchFiles,
|
||||
|
||||
/**
|
||||
* The Messages tab shown in the global search screen on Mobile.
|
||||
*/
|
||||
MobileSearchMessages,
|
||||
|
||||
/**
|
||||
* The People tab shown in the global search screen on Mobile.
|
||||
*/
|
||||
MobileSearchPeople,
|
||||
|
||||
/**
|
||||
* The Rooms tab shown in the global search screen on Mobile.
|
||||
*/
|
||||
MobileSearchRooms,
|
||||
|
||||
/**
|
||||
* The sidebar shown on mobile with spaces, settings etc.
|
||||
*/
|
||||
MobileSidebar,
|
||||
|
||||
/**
|
||||
* The screen shown to select which room directory you'd like to use.
|
||||
*/
|
||||
MobileSwitchDirectory,
|
||||
|
||||
/**
|
||||
* Legacy: The screen that shows all groups/communities you have joined.
|
||||
*/
|
||||
MyGroups,
|
||||
|
||||
/**
|
||||
* The screen that displays the registration flow (when the user wants
|
||||
* to create an account)
|
||||
*/
|
||||
Register,
|
||||
|
||||
/**
|
||||
* The screen that displays the messages and events received in a room.
|
||||
*/
|
||||
Room,
|
||||
|
||||
/**
|
||||
* The screen shown when tapping the name of a room from the Room
|
||||
* screen.
|
||||
*/
|
||||
RoomDetails,
|
||||
|
||||
/**
|
||||
* The screen that lists public rooms for you to discover.
|
||||
*/
|
||||
RoomDirectory,
|
||||
|
||||
/**
|
||||
* The screen that lists all the user's rooms and let them filter the
|
||||
* rooms.
|
||||
*/
|
||||
RoomFilter,
|
||||
|
||||
/**
|
||||
* The screen that displays the list of members that are part of a room.
|
||||
*/
|
||||
RoomMembers,
|
||||
|
||||
/**
|
||||
* The notifications settings screen shown from the Room Details screen.
|
||||
*/
|
||||
RoomNotifications,
|
||||
|
||||
/**
|
||||
* The screen that allows you to search for messages/files in a specific
|
||||
* room.
|
||||
*/
|
||||
RoomSearch,
|
||||
|
||||
/**
|
||||
* The settings screen shown from the Room Details screen.
|
||||
*/
|
||||
RoomSettings,
|
||||
|
||||
/**
|
||||
* The screen that allows you to see all of the files sent in a specific
|
||||
* room.
|
||||
*/
|
||||
RoomUploads,
|
||||
|
||||
/**
|
||||
* The global settings screen shown in the app.
|
||||
*/
|
||||
Settings,
|
||||
|
||||
/**
|
||||
* The settings screen to change the default notification options.
|
||||
*/
|
||||
SettingsDefaultNotifications,
|
||||
|
||||
/**
|
||||
* The settings screen to manage notification mentions and keywords.
|
||||
*/
|
||||
SettingsMentionsAndKeywords,
|
||||
|
||||
/**
|
||||
* The global security settings screen.
|
||||
*/
|
||||
SettingsSecurity,
|
||||
|
||||
/**
|
||||
* The screen shown to create a new direct room.
|
||||
*/
|
||||
StartChat,
|
||||
|
||||
/**
|
||||
* A screen that shows information about a room member.
|
||||
*/
|
||||
User,
|
||||
|
||||
/**
|
||||
* ?
|
||||
*/
|
||||
WebCompleteSecurity,
|
||||
|
||||
/**
|
||||
* ?
|
||||
*/
|
||||
WebE2ESetup,
|
||||
WebForgotPassword,
|
||||
|
||||
/**
|
||||
* ?
|
||||
*/
|
||||
WebLoading,
|
||||
WebLogin,
|
||||
WebRegister,
|
||||
|
||||
/**
|
||||
* ?
|
||||
*/
|
||||
WebSoftLogout,
|
||||
WebWelcome,
|
||||
|
||||
/**
|
||||
* The splash screen.
|
||||
*/
|
||||
Welcome,
|
||||
}
|
||||
|
||||
override fun getName() = screenName.name
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.analytics.plan
|
||||
|
||||
import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
|
||||
|
||||
// GENERATED FILE, DO NOT EDIT. FOR MORE INFORMATION VISIT
|
||||
// https://github.com/matrix-org/matrix-analytics-events/
|
||||
|
||||
/**
|
||||
* Triggered when the user becomes unauthenticated without actually clicking
|
||||
* sign out(E.g. Due to expiry of an access token without a way to refresh).
|
||||
*/
|
||||
data class UnauthenticatedError(
|
||||
/**
|
||||
* The error code as defined in matrix spec. The source of this error is
|
||||
* from the homeserver.
|
||||
*/
|
||||
val errorCode: ErrorCode,
|
||||
/**
|
||||
* The reason for the error. The source of this error is from the
|
||||
* homeserver, the reason can vary and is subject to change so there is
|
||||
* no enum of possible values.
|
||||
*/
|
||||
val errorReason: String,
|
||||
/**
|
||||
* Whether the auth mechanism is refresh-token-based.
|
||||
*/
|
||||
val refreshTokenAuth: Boolean,
|
||||
/**
|
||||
* Whether a soft logout or hard logout was triggered.
|
||||
*/
|
||||
val softLogout: Boolean,
|
||||
) : VectorAnalyticsEvent {
|
||||
|
||||
enum class ErrorCode {
|
||||
M_FORBIDDEN,
|
||||
M_UNKNOWN,
|
||||
M_UNKNOWN_TOKEN,
|
||||
}
|
||||
|
||||
override fun getName() = "UnauthenticatedError"
|
||||
|
||||
override fun getProperties(): Map<String, Any>? {
|
||||
return mutableMapOf<String, Any>().apply {
|
||||
put("errorCode", errorCode.name)
|
||||
put("errorReason", errorReason)
|
||||
put("refreshTokenAuth", refreshTokenAuth)
|
||||
put("softLogout", softLogout)
|
||||
}.takeIf { it.isNotEmpty() }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.analytics.screen
|
||||
|
||||
import android.os.SystemClock
|
||||
import im.vector.app.features.analytics.AnalyticsTracker
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* Track a screen display. Unique usage.
|
||||
*/
|
||||
class ScreenEvent(val screenName: Screen.ScreenName) {
|
||||
private val startTime = SystemClock.elapsedRealtime()
|
||||
|
||||
// Protection to avoid multiple sending
|
||||
private var isSent = false
|
||||
|
||||
/**
|
||||
* @param screenNameOverride can be used to override the screen name passed in constructor parameter
|
||||
*/
|
||||
fun send(analyticsTracker: AnalyticsTracker,
|
||||
screenNameOverride: Screen.ScreenName? = null) {
|
||||
if (isSent) {
|
||||
Timber.w("Event $screenName Already sent!")
|
||||
return
|
||||
}
|
||||
isSent = true
|
||||
analyticsTracker.screen(
|
||||
Screen(
|
||||
screenName = screenNameOverride ?: screenName,
|
||||
durationMs = (SystemClock.elapsedRealtime() - startTime).toInt()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
package im.vector.app.features.call.dialpad
|
||||
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.os.Bundle
|
||||
import android.telephony.PhoneNumberFormattingTextWatcher
|
||||
|
@ -37,6 +38,10 @@ import androidx.fragment.app.Fragment
|
|||
import com.android.dialer.dialpadview.DialpadView
|
||||
import com.android.dialer.dialpadview.DigitsEditText
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.singletonEntryPoint
|
||||
import im.vector.app.features.analytics.AnalyticsTracker
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import im.vector.app.features.analytics.screen.ScreenEvent
|
||||
import im.vector.app.features.themes.ThemeUtils
|
||||
|
||||
class DialPadFragment : Fragment(), TextWatcher {
|
||||
|
@ -53,6 +58,25 @@ class DialPadFragment : Fragment(), TextWatcher {
|
|||
private var enableDelete = true
|
||||
private var enableFabOk = true
|
||||
|
||||
private lateinit var analyticsTracker: AnalyticsTracker
|
||||
|
||||
override fun onAttach(context: Context) {
|
||||
super.onAttach(context)
|
||||
val singletonEntryPoint = context.singletonEntryPoint()
|
||||
analyticsTracker = singletonEntryPoint.analyticsTracker()
|
||||
}
|
||||
|
||||
private var screenEvent: ScreenEvent? = null
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
screenEvent = ScreenEvent(Screen.ScreenName.MobileDialpad)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
screenEvent?.send(analyticsTracker)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
|
|
|
@ -270,6 +270,10 @@ class WebRtcCall(
|
|||
}
|
||||
}
|
||||
|
||||
fun durationMillis(): Int {
|
||||
return timer.elapsedTime().toInt()
|
||||
}
|
||||
|
||||
fun formattedDuration(): String {
|
||||
return formatDuration(
|
||||
Duration.ofMillis(timer.elapsedTime())
|
||||
|
|
|
@ -22,6 +22,9 @@ import androidx.lifecycle.LifecycleOwner
|
|||
import im.vector.app.ActiveSessionDataSource
|
||||
import im.vector.app.BuildConfig
|
||||
import im.vector.app.core.services.CallService
|
||||
import im.vector.app.features.analytics.AnalyticsTracker
|
||||
import im.vector.app.features.analytics.plan.CallEnded
|
||||
import im.vector.app.features.analytics.plan.CallStarted
|
||||
import im.vector.app.features.call.VectorCallActivity
|
||||
import im.vector.app.features.call.audio.CallAudioManager
|
||||
import im.vector.app.features.call.lookup.CallProtocolsChecker
|
||||
|
@ -68,7 +71,8 @@ private val loggerTag = LoggerTag("WebRtcCallManager", LoggerTag.VOIP)
|
|||
@Singleton
|
||||
class WebRtcCallManager @Inject constructor(
|
||||
private val context: Context,
|
||||
private val activeSessionDataSource: ActiveSessionDataSource
|
||||
private val activeSessionDataSource: ActiveSessionDataSource,
|
||||
private val analyticsTracker: AnalyticsTracker
|
||||
) : CallListener,
|
||||
DefaultLifecycleObserver {
|
||||
|
||||
|
@ -237,6 +241,7 @@ class WebRtcCallManager @Inject constructor(
|
|||
val currentCall = getCurrentCall().takeIf { it != call }
|
||||
currentCall?.updateRemoteOnHold(onHold = true)
|
||||
audioManager.setMode(if (call.mxCall.isVideoCall) CallAudioManager.Mode.VIDEO_CALL else CallAudioManager.Mode.AUDIO_CALL)
|
||||
call.trackCallStarted()
|
||||
this.currentCall.setAndNotify(call)
|
||||
}
|
||||
|
||||
|
@ -245,6 +250,7 @@ class WebRtcCallManager @Inject constructor(
|
|||
val webRtcCall = callsByCallId.remove(callId) ?: return Unit.also {
|
||||
Timber.tag(loggerTag.value).v("On call ended for unknown call $callId")
|
||||
}
|
||||
webRtcCall.trackCallEnded()
|
||||
CallService.onCallTerminated(context, callId, endCallReason, rejected)
|
||||
callsByRoomId[webRtcCall.signalingRoomId]?.remove(webRtcCall)
|
||||
callsByRoomId[webRtcCall.nativeRoomId]?.remove(webRtcCall)
|
||||
|
@ -443,4 +449,28 @@ class WebRtcCallManager @Inject constructor(
|
|||
}
|
||||
call.onCallAssertedIdentityReceived(callAssertedIdentityContent)
|
||||
}
|
||||
|
||||
/**
|
||||
* Analytics
|
||||
*/
|
||||
private fun WebRtcCall.trackCallStarted() {
|
||||
analyticsTracker.capture(
|
||||
CallStarted(
|
||||
isVideo = mxCall.isVideoCall,
|
||||
numParticipants = 2,
|
||||
placed = mxCall.isOutgoing
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun WebRtcCall.trackCallEnded() {
|
||||
analyticsTracker.capture(
|
||||
CallEnded(
|
||||
durationMs = durationMillis(),
|
||||
isVideo = mxCall.isVideoCall,
|
||||
numParticipants = 2,
|
||||
placed = mxCall.isOutgoing
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
|||
import im.vector.app.core.utils.checkPermissions
|
||||
import im.vector.app.core.utils.onPermissionDeniedSnackbar
|
||||
import im.vector.app.core.utils.registerForPermissionsResult
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import im.vector.app.features.contactsbook.ContactsBookFragment
|
||||
import im.vector.app.features.userdirectory.UserListFragment
|
||||
import im.vector.app.features.userdirectory.UserListFragmentArgs
|
||||
|
@ -63,6 +64,7 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() {
|
|||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
analyticsScreenName = Screen.ScreenName.StartChat
|
||||
views.toolbar.visibility = View.GONE
|
||||
|
||||
sharedActionViewModel = viewModelProvider.get(UserListSharedActionViewModel::class.java)
|
||||
|
|
|
@ -24,6 +24,7 @@ import android.os.Bundle
|
|||
import android.os.Parcelable
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
|
@ -49,6 +50,8 @@ import im.vector.app.databinding.ActivityHomeBinding
|
|||
import im.vector.app.features.MainActivity
|
||||
import im.vector.app.features.MainActivityArgs
|
||||
import im.vector.app.features.analytics.accountdata.AnalyticsAccountDataViewModel
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import im.vector.app.features.analytics.screen.ScreenEvent
|
||||
import im.vector.app.features.disclaimer.showDisclaimerDialog
|
||||
import im.vector.app.features.matrixto.MatrixToBottomSheet
|
||||
import im.vector.app.features.navigation.Navigator
|
||||
|
@ -104,6 +107,7 @@ class HomeActivity :
|
|||
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
|
||||
|
||||
private val homeActivityViewModel: HomeActivityViewModel by viewModel()
|
||||
|
||||
@Suppress("UNUSED")
|
||||
private val analyticsAccountDataViewModel: AnalyticsAccountDataViewModel by viewModel()
|
||||
@Suppress("UNUSED")
|
||||
|
@ -164,6 +168,16 @@ class HomeActivity :
|
|||
}
|
||||
|
||||
private val drawerListener = object : DrawerLayout.SimpleDrawerListener() {
|
||||
private var drawerScreenEvent: ScreenEvent? = null
|
||||
override fun onDrawerOpened(drawerView: View) {
|
||||
drawerScreenEvent = ScreenEvent(Screen.ScreenName.MobileSidebar)
|
||||
}
|
||||
|
||||
override fun onDrawerClosed(drawerView: View) {
|
||||
drawerScreenEvent?.send(analyticsTracker)
|
||||
drawerScreenEvent = null
|
||||
}
|
||||
|
||||
override fun onDrawerStateChanged(newState: Int) {
|
||||
hideKeyboard()
|
||||
}
|
||||
|
@ -175,6 +189,7 @@ class HomeActivity :
|
|||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
analyticsScreenName = Screen.ScreenName.Home
|
||||
supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, false)
|
||||
FcmHelper.ensureFcmTokenIsRetrieved(this, pushManager, vectorPreferences.areNotificationEnabledForDevice())
|
||||
sharedActionViewModel = viewModelProvider.get(HomeSharedActionViewModel::class.java)
|
||||
|
|
|
@ -30,6 +30,7 @@ import im.vector.app.core.extensions.replaceChildFragment
|
|||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.utils.startSharePlainTextIntent
|
||||
import im.vector.app.databinding.FragmentHomeDrawerBinding
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import im.vector.app.features.settings.VectorSettingsActivity
|
||||
import im.vector.app.features.spaces.SpaceListFragment
|
||||
|
@ -97,6 +98,7 @@ class HomeDrawerFragment @Inject constructor(
|
|||
|
||||
views.homeDrawerInviteFriendButton.debouncedClicks {
|
||||
session.permalinkService().createPermalink(sharedActionViewModel.session.myUserId)?.let { permalink ->
|
||||
analyticsTracker.screen(Screen(screenName = Screen.ScreenName.MobileInviteFriends))
|
||||
val text = getString(R.string.invite_friends_text, permalink)
|
||||
|
||||
startSharePlainTextIntent(
|
||||
|
|
|
@ -19,6 +19,7 @@ package im.vector.app.features.home.room.detail
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
|
@ -36,6 +37,8 @@ import im.vector.app.core.extensions.replaceFragment
|
|||
import im.vector.app.core.platform.ToolbarConfigurable
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.databinding.ActivityRoomDetailBinding
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import im.vector.app.features.analytics.screen.ScreenEvent
|
||||
import im.vector.app.features.home.room.breadcrumbs.BreadcrumbsFragment
|
||||
import im.vector.app.features.home.room.detail.timeline.helper.VoiceMessagePlaybackTracker
|
||||
import im.vector.app.features.matrixto.MatrixToBottomSheet
|
||||
|
@ -161,6 +164,16 @@ class RoomDetailActivity :
|
|||
}
|
||||
|
||||
private val drawerListener = object : DrawerLayout.SimpleDrawerListener() {
|
||||
private var drawerScreenEvent: ScreenEvent? = null
|
||||
override fun onDrawerOpened(drawerView: View) {
|
||||
drawerScreenEvent = ScreenEvent(Screen.ScreenName.MobileBreadcrumbs)
|
||||
}
|
||||
|
||||
override fun onDrawerClosed(drawerView: View) {
|
||||
drawerScreenEvent?.send(analyticsTracker)
|
||||
drawerScreenEvent = null
|
||||
}
|
||||
|
||||
override fun onDrawerStateChanged(newState: Int) {
|
||||
hideKeyboard()
|
||||
|
||||
|
|
|
@ -116,6 +116,8 @@ import im.vector.app.core.utils.startInstallFromSourceIntent
|
|||
import im.vector.app.core.utils.toast
|
||||
import im.vector.app.databinding.DialogReportContentBinding
|
||||
import im.vector.app.databinding.FragmentRoomDetailBinding
|
||||
import im.vector.app.features.analytics.plan.Click
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import im.vector.app.features.attachments.AttachmentTypeSelectorView
|
||||
import im.vector.app.features.attachments.AttachmentsHelper
|
||||
import im.vector.app.features.attachments.ContactAttachment
|
||||
|
@ -336,6 +338,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
analyticsScreenName = Screen.ScreenName.Room
|
||||
setFragmentResultListener(MigrateRoomBottomSheet.REQUEST_KEY) { _, bundle ->
|
||||
bundle.getString(MigrateRoomBottomSheet.BUNDLE_KEY_REPLACEMENT_ROOM)?.let { replacementRoomId ->
|
||||
roomDetailViewModel.handle(RoomDetailAction.RoomUpgradeSuccess(replacementRoomId))
|
||||
|
@ -1396,6 +1399,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
return
|
||||
}
|
||||
if (text.isNotBlank()) {
|
||||
analyticsTracker.capture(Click(name = Click.Name.SendMessageButton))
|
||||
// We collapse ASAP, if not there will be a slight annoying delay
|
||||
views.composerLayout.collapse(true)
|
||||
lockSendButton = true
|
||||
|
|
|
@ -38,7 +38,9 @@ import im.vector.app.core.mvrx.runCatchingToAsync
|
|||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.core.utils.BehaviorDataSource
|
||||
import im.vector.app.features.analytics.AnalyticsTracker
|
||||
import im.vector.app.features.analytics.DecryptionFailureTracker
|
||||
import im.vector.app.features.analytics.extensions.toAnalyticsJoinedRoom
|
||||
import im.vector.app.features.call.conference.ConferenceEvent
|
||||
import im.vector.app.features.call.conference.JitsiActiveConferenceHolder
|
||||
import im.vector.app.features.call.conference.JitsiService
|
||||
|
@ -114,6 +116,7 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||
private val chatEffectManager: ChatEffectManager,
|
||||
private val directRoomHelper: DirectRoomHelper,
|
||||
private val jitsiService: JitsiService,
|
||||
private val analyticsTracker: AnalyticsTracker,
|
||||
private val activeConferenceHolder: JitsiActiveConferenceHolder,
|
||||
private val decryptionFailureTracker: DecryptionFailureTracker,
|
||||
timelineFactory: TimelineFactory,
|
||||
|
@ -730,7 +733,10 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||
|
||||
private fun handleAcceptInvite() {
|
||||
viewModelScope.launch {
|
||||
tryOrNull { room.join() }
|
||||
tryOrNull {
|
||||
room.join()
|
||||
analyticsTracker.capture(room.roomSummary().toAnalyticsJoinedRoom())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory
|
|||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.analytics.AnalyticsTracker
|
||||
import im.vector.app.features.analytics.extensions.toAnalyticsJoinedRoom
|
||||
import im.vector.app.features.attachments.toContentAttachmentData
|
||||
import im.vector.app.features.command.CommandParser
|
||||
import im.vector.app.features.command.ParsedCommand
|
||||
|
@ -69,6 +71,7 @@ class MessageComposerViewModel @AssistedInject constructor(
|
|||
private val commandParser: CommandParser,
|
||||
private val rainbowGenerator: RainbowGenerator,
|
||||
private val voiceMessageHelper: VoiceMessageHelper,
|
||||
private val analyticsTracker: AnalyticsTracker,
|
||||
private val voicePlayerHelper: VoicePlayerHelper
|
||||
) : VectorViewModel<MessageComposerViewState, MessageComposerAction, MessageComposerViewEvents>(initialState) {
|
||||
|
||||
|
@ -521,6 +524,7 @@ class MessageComposerViewModel @AssistedInject constructor(
|
|||
return@launch
|
||||
}
|
||||
session.getRoomSummary(command.roomAlias)
|
||||
?.also { analyticsTracker.capture(it.toAnalyticsJoinedRoom()) }
|
||||
?.roomId
|
||||
?.let {
|
||||
_viewEvents.post(MessageComposerViewEvents.JoinRoomCommandSuccess(it))
|
||||
|
|
|
@ -24,6 +24,7 @@ import dagger.hilt.android.AndroidEntryPoint
|
|||
import im.vector.app.core.extensions.replaceFragment
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.databinding.ActivityFilteredRoomsBinding
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import im.vector.app.features.home.RoomListDisplayMode
|
||||
import im.vector.app.features.home.room.list.RoomListFragment
|
||||
import im.vector.app.features.home.room.list.RoomListParams
|
||||
|
@ -42,6 +43,7 @@ class FilteredRoomsActivity : VectorBaseActivity<ActivityFilteredRoomsBinding>()
|
|||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
analyticsScreenName = Screen.ScreenName.RoomFilter
|
||||
configureToolbar(views.filteredRoomsToolbar)
|
||||
if (isFirstCreation()) {
|
||||
val params = RoomListParams(RoomListDisplayMode.FILTERED)
|
||||
|
|
|
@ -42,6 +42,7 @@ import im.vector.app.core.platform.StateView
|
|||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.resources.UserPreferencesProvider
|
||||
import im.vector.app.databinding.FragmentRoomListBinding
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import im.vector.app.features.home.RoomListDisplayMode
|
||||
import im.vector.app.features.home.room.filtered.FilteredRoomFooterItem
|
||||
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet
|
||||
|
@ -100,6 +101,15 @@ class RoomListFragment @Inject constructor(
|
|||
private val adapterInfosList = mutableListOf<SectionAdapterInfo>()
|
||||
private var concatAdapter: ConcatAdapter? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
analyticsScreenName = when (roomListParams.displayMode) {
|
||||
RoomListDisplayMode.PEOPLE -> Screen.ScreenName.MobilePeople
|
||||
RoomListDisplayMode.ROOMS -> Screen.ScreenName.MobileRooms
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
views.stateView.contentView = views.roomListView
|
||||
|
|
|
@ -32,6 +32,8 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory
|
|||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.analytics.AnalyticsTracker
|
||||
import im.vector.app.features.analytics.extensions.toAnalyticsJoinedRoom
|
||||
import im.vector.app.features.displayname.getBestName
|
||||
import im.vector.app.features.invite.AutoAcceptInvites
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
|
@ -56,7 +58,8 @@ class RoomListViewModel @AssistedInject constructor(
|
|||
stringProvider: StringProvider,
|
||||
appStateHandler: AppStateHandler,
|
||||
vectorPreferences: VectorPreferences,
|
||||
autoAcceptInvites: AutoAcceptInvites
|
||||
autoAcceptInvites: AutoAcceptInvites,
|
||||
private val analyticsTracker: AnalyticsTracker
|
||||
) : VectorViewModel<RoomListViewState, RoomListAction, RoomListViewEvents>(initialState) {
|
||||
|
||||
@AssistedFactory
|
||||
|
@ -223,6 +226,7 @@ class RoomListViewModel @AssistedInject constructor(
|
|||
viewModelScope.launch {
|
||||
try {
|
||||
room.join()
|
||||
analyticsTracker.capture(action.roomSummary.toAnalyticsJoinedRoom())
|
||||
// We do not update the joiningRoomsIds here, because, the room is not joined yet regarding the sync data.
|
||||
// Instead, we wait for the room to be joined
|
||||
} catch (failure: Throwable) {
|
||||
|
|
|
@ -40,6 +40,7 @@ import im.vector.app.core.extensions.exhaustive
|
|||
import im.vector.app.core.platform.ToolbarConfigurable
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.databinding.ActivityLoginBinding
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import im.vector.app.features.home.HomeActivity
|
||||
import im.vector.app.features.login.terms.LoginTermsFragment
|
||||
import im.vector.app.features.login.terms.LoginTermsFragmentArgument
|
||||
|
@ -82,6 +83,8 @@ open class LoginActivity : VectorBaseActivity<ActivityLoginBinding>(), ToolbarCo
|
|||
override fun getCoordinatorLayout() = views.coordinatorLayout
|
||||
|
||||
override fun initUiAndData() {
|
||||
analyticsScreenName = Screen.ScreenName.Login
|
||||
|
||||
if (isFirstCreation()) {
|
||||
addFirstFragment()
|
||||
}
|
||||
|
@ -200,6 +203,10 @@ open class LoginActivity : VectorBaseActivity<ActivityLoginBinding>(), ToolbarCo
|
|||
|
||||
private fun updateWithState(loginViewState: LoginViewState) {
|
||||
if (loginViewState.isUserLogged()) {
|
||||
if (loginViewState.signMode == SignMode.SignUp) {
|
||||
// change the screen name
|
||||
analyticsScreenName = Screen.ScreenName.Register
|
||||
}
|
||||
val intent = HomeActivity.newIntent(
|
||||
this,
|
||||
accountCreation = loginViewState.signMode == SignMode.SignUp
|
||||
|
|
|
@ -31,6 +31,7 @@ import im.vector.app.core.extensions.hidePassword
|
|||
import im.vector.app.core.extensions.isEmail
|
||||
import im.vector.app.core.extensions.toReducedUrl
|
||||
import im.vector.app.databinding.FragmentLoginResetPasswordBinding
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
@ -46,6 +47,11 @@ class LoginResetPasswordFragment @Inject constructor() : AbstractLoginFragment<F
|
|||
// Show warning only once
|
||||
private var showWarning = true
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
analyticsScreenName = Screen.ScreenName.ForgotPassword
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginResetPasswordBinding {
|
||||
return FragmentLoginResetPasswordBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|||
import im.vector.app.BuildConfig
|
||||
import im.vector.app.R
|
||||
import im.vector.app.databinding.FragmentLoginSplashBinding
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import org.matrix.android.sdk.api.failure.Failure
|
||||
import java.net.UnknownHostException
|
||||
|
@ -42,6 +43,11 @@ class LoginSplashFragment @Inject constructor(
|
|||
return FragmentLoginSplashBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
analyticsScreenName = Screen.ScreenName.Welcome
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@ import androidx.core.app.RemoteInput
|
|||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.di.ActiveSessionHolder
|
||||
import im.vector.app.features.analytics.AnalyticsTracker
|
||||
import im.vector.app.features.analytics.extensions.toAnalyticsJoinedRoom
|
||||
import im.vector.app.features.session.coroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
|
@ -41,6 +43,7 @@ class NotificationBroadcastReceiver : BroadcastReceiver() {
|
|||
|
||||
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager
|
||||
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
|
||||
@Inject lateinit var analyticsTracker: AnalyticsTracker
|
||||
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
if (intent == null || context == null) return
|
||||
|
@ -79,7 +82,10 @@ class NotificationBroadcastReceiver : BroadcastReceiver() {
|
|||
val room = session.getRoom(roomId)
|
||||
if (room != null) {
|
||||
session.coroutineScope.launch {
|
||||
tryOrNull { room.join() }
|
||||
tryOrNull {
|
||||
room.join()
|
||||
analyticsTracker.capture(room.roomSummary().toAnalyticsJoinedRoom())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -160,7 +160,7 @@ class PublicRoomsFragment @Inject constructor(
|
|||
|
||||
override fun onPublicRoomJoin(publicRoom: PublicRoom) {
|
||||
Timber.v("PublicRoomJoinClicked: $publicRoom")
|
||||
viewModel.handle(RoomDirectoryAction.JoinRoom(publicRoom.roomId))
|
||||
viewModel.handle(RoomDirectoryAction.JoinRoom(publicRoom))
|
||||
}
|
||||
|
||||
override fun loadMore() {
|
||||
|
|
|
@ -17,10 +17,11 @@
|
|||
package im.vector.app.features.roomdirectory
|
||||
|
||||
import im.vector.app.core.platform.VectorViewModelAction
|
||||
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
|
||||
|
||||
sealed class RoomDirectoryAction : VectorViewModelAction {
|
||||
data class SetRoomDirectoryData(val roomDirectoryData: RoomDirectoryData) : RoomDirectoryAction()
|
||||
data class FilterWith(val filter: String) : RoomDirectoryAction()
|
||||
object LoadMore : RoomDirectoryAction()
|
||||
data class JoinRoom(val roomId: String) : RoomDirectoryAction()
|
||||
data class JoinRoom(val publicRoom: PublicRoom) : RoomDirectoryAction()
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import im.vector.app.core.extensions.addFragmentToBackstack
|
|||
import im.vector.app.core.extensions.popBackstack
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.databinding.ActivitySimpleBinding
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import im.vector.app.features.matrixto.MatrixToBottomSheet
|
||||
import im.vector.app.features.navigation.Navigator
|
||||
import im.vector.app.features.roomdirectory.createroom.CreateRoomArgs
|
||||
|
@ -50,6 +51,7 @@ class RoomDirectoryActivity : VectorBaseActivity<ActivitySimpleBinding>(), Matri
|
|||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
analyticsScreenName = Screen.ScreenName.RoomDirectory
|
||||
sharedActionViewModel = viewModelProvider.get(RoomDirectorySharedActionViewModel::class.java)
|
||||
|
||||
if (isFirstCreation()) {
|
||||
|
|
|
@ -27,6 +27,8 @@ import dagger.assisted.AssistedInject
|
|||
import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
||||
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.features.analytics.AnalyticsTracker
|
||||
import im.vector.app.features.analytics.extensions.toAnalyticsJoinedRoom
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.Job
|
||||
|
@ -45,6 +47,7 @@ class RoomDirectoryViewModel @AssistedInject constructor(
|
|||
@Assisted initialState: PublicRoomsViewState,
|
||||
vectorPreferences: VectorPreferences,
|
||||
private val session: Session,
|
||||
private val analyticsTracker: AnalyticsTracker,
|
||||
private val explicitTermFilter: ExplicitTermFilter
|
||||
) : VectorViewModel<PublicRoomsViewState, RoomDirectoryAction, RoomDirectoryViewEvents>(initialState) {
|
||||
|
||||
|
@ -213,7 +216,7 @@ class RoomDirectoryViewModel @AssistedInject constructor(
|
|||
}
|
||||
|
||||
private fun joinRoom(action: RoomDirectoryAction.JoinRoom) = withState { state ->
|
||||
val roomMembershipChange = state.changeMembershipStates[action.roomId]
|
||||
val roomMembershipChange = state.changeMembershipStates[action.publicRoom.roomId]
|
||||
if (roomMembershipChange?.isInProgress().orFalse()) {
|
||||
// Request already sent, should not happen
|
||||
Timber.w("Try to join an already joining room. Should not happen")
|
||||
|
@ -222,7 +225,8 @@ class RoomDirectoryViewModel @AssistedInject constructor(
|
|||
val viaServers = listOfNotNull(state.roomDirectoryData.homeServer)
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
session.joinRoom(action.roomId, viaServers = viaServers)
|
||||
session.joinRoom(action.publicRoom.roomId, viaServers = viaServers)
|
||||
analyticsTracker.capture(action.publicRoom.toAnalyticsJoinedRoom())
|
||||
// We do not update the joiningRoomsIds here, because, the room is not joined yet regarding the sync data.
|
||||
// Instead, we wait for the room to be joined
|
||||
} catch (failure: Throwable) {
|
||||
|
|
|
@ -28,6 +28,7 @@ import im.vector.app.core.extensions.addFragment
|
|||
import im.vector.app.core.platform.ToolbarConfigurable
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.databinding.ActivitySimpleBinding
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import im.vector.app.features.roomdirectory.RoomDirectorySharedAction
|
||||
import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
|
@ -62,6 +63,7 @@ class CreateRoomActivity : VectorBaseActivity<ActivitySimpleBinding>(), ToolbarC
|
|||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
analyticsScreenName = Screen.ScreenName.CreateRoom
|
||||
sharedActionViewModel = viewModelProvider.get(RoomDirectorySharedActionViewModel::class.java)
|
||||
sharedActionViewModel
|
||||
.stream()
|
||||
|
|
|
@ -30,6 +30,8 @@ import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
|||
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.features.analytics.AnalyticsTracker
|
||||
import im.vector.app.features.analytics.plan.CreatedRoom
|
||||
import im.vector.app.features.raw.wellknown.getElementWellknown
|
||||
import im.vector.app.features.raw.wellknown.isE2EByDefault
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
@ -52,10 +54,12 @@ import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
|
|||
import org.matrix.android.sdk.api.session.room.model.create.RestrictedRoomPreset
|
||||
import timber.log.Timber
|
||||
|
||||
class CreateRoomViewModel @AssistedInject constructor(@Assisted private val initialState: CreateRoomViewState,
|
||||
private val session: Session,
|
||||
private val rawService: RawService,
|
||||
appStateHandler: AppStateHandler
|
||||
class CreateRoomViewModel @AssistedInject constructor(
|
||||
@Assisted private val initialState: CreateRoomViewState,
|
||||
private val session: Session,
|
||||
private val rawService: RawService,
|
||||
appStateHandler: AppStateHandler,
|
||||
private val analyticsTracker: AnalyticsTracker
|
||||
) : VectorViewModel<CreateRoomViewState, CreateRoomAction, CreateRoomViewEvents>(initialState) {
|
||||
|
||||
@AssistedFactory
|
||||
|
@ -296,7 +300,7 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted private val init
|
|||
viewModelScope.launch {
|
||||
runCatching { session.createRoom(createRoomParams) }.fold(
|
||||
{ roomId ->
|
||||
|
||||
analyticsTracker.capture(CreatedRoom(isDM = createRoomParams.isDirect.orFalse()))
|
||||
if (state.parentSpaceId != null) {
|
||||
// add it as a child
|
||||
try {
|
||||
|
|
|
@ -30,6 +30,7 @@ import im.vector.app.core.extensions.configureWith
|
|||
import im.vector.app.core.platform.OnBackPressed
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.databinding.FragmentRoomDirectoryPickerBinding
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import im.vector.app.features.roomdirectory.RoomDirectoryAction
|
||||
import im.vector.app.features.roomdirectory.RoomDirectoryData
|
||||
import im.vector.app.features.roomdirectory.RoomDirectoryServer
|
||||
|
@ -52,6 +53,11 @@ class RoomDirectoryPickerFragment @Inject constructor(private val roomDirectoryP
|
|||
return FragmentRoomDirectoryPickerBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
analyticsScreenName = Screen.ScreenName.MobileSwitchDirectory
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ data class RoomPreviewData(
|
|||
val roomAlias: String? = null,
|
||||
val roomType: String? = null,
|
||||
val topic: String? = null,
|
||||
val numJoinedMembers: Int? = null,
|
||||
val worldReadable: Boolean = false,
|
||||
val avatarUrl: String? = null,
|
||||
val homeServers: List<String> = emptyList(),
|
||||
|
@ -69,6 +70,7 @@ class RoomPreviewActivity : VectorBaseActivity<ActivitySimpleBinding>(), Toolbar
|
|||
roomName = publicRoom.name,
|
||||
roomAlias = publicRoom.getPrimaryAlias(),
|
||||
topic = publicRoom.topic,
|
||||
numJoinedMembers = publicRoom.numJoinedMembers,
|
||||
worldReadable = publicRoom.worldReadable,
|
||||
avatarUrl = publicRoom.avatarUrl,
|
||||
homeServers = listOfNotNull(roomDirectoryData.homeServer)
|
||||
|
|
|
@ -27,6 +27,9 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory
|
|||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.platform.EmptyViewEvents
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.features.analytics.AnalyticsTracker
|
||||
import im.vector.app.features.analytics.extensions.toAnalyticsRoomSize
|
||||
import im.vector.app.features.analytics.plan.JoinedRoom
|
||||
import im.vector.app.features.roomdirectory.JoinState
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
|
@ -44,9 +47,11 @@ import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
|||
import org.matrix.android.sdk.flow.flow
|
||||
import timber.log.Timber
|
||||
|
||||
class RoomPreviewViewModel @AssistedInject constructor(@Assisted private val initialState: RoomPreviewViewState,
|
||||
private val session: Session) :
|
||||
VectorViewModel<RoomPreviewViewState, RoomPreviewAction, EmptyViewEvents>(initialState) {
|
||||
class RoomPreviewViewModel @AssistedInject constructor(
|
||||
@Assisted private val initialState: RoomPreviewViewState,
|
||||
private val analyticsTracker: AnalyticsTracker,
|
||||
private val session: Session
|
||||
) : VectorViewModel<RoomPreviewViewState, RoomPreviewAction, EmptyViewEvents>(initialState) {
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : MavericksAssistedViewModelFactory<RoomPreviewViewModel, RoomPreviewViewState> {
|
||||
|
@ -243,6 +248,11 @@ class RoomPreviewViewModel @AssistedInject constructor(@Assisted private val ini
|
|||
viewModelScope.launch {
|
||||
try {
|
||||
session.joinRoom(state.roomId, viaServers = state.homeServers)
|
||||
analyticsTracker.capture(JoinedRoom(
|
||||
// Always false in this case (?)
|
||||
isDM = false,
|
||||
roomSize = state.numJoinMembers.toAnalyticsRoomSize()
|
||||
))
|
||||
// We do not update the joiningRoomsIds here, because, the room is not joined yet regarding the sync data.
|
||||
// Instead, we wait for the room to be joined
|
||||
} catch (failure: Throwable) {
|
||||
|
|
|
@ -33,6 +33,7 @@ data class RoomPreviewViewState(
|
|||
|
||||
val roomName: String? = null,
|
||||
val roomTopic: String? = null,
|
||||
val numJoinMembers: Int? = null,
|
||||
val avatarUrl: String? = null,
|
||||
|
||||
val shouldPeekFromServer: Boolean = false,
|
||||
|
@ -56,6 +57,7 @@ data class RoomPreviewViewState(
|
|||
homeServers = args.homeServers,
|
||||
roomName = args.roomName,
|
||||
roomTopic = args.topic,
|
||||
numJoinMembers = args.numJoinedMembers,
|
||||
avatarUrl = args.avatarUrl,
|
||||
shouldPeekFromServer = args.peekFromServer,
|
||||
fromEmailInvite = args.fromEmailInvite,
|
||||
|
@ -64,6 +66,6 @@ data class RoomPreviewViewState(
|
|||
|
||||
fun matrixItem(): MatrixItem {
|
||||
return if (roomType == RoomType.SPACE) MatrixItem.SpaceItem(roomId, roomName ?: roomAlias, avatarUrl)
|
||||
else MatrixItem.RoomItem(roomId, roomName ?: roomAlias, avatarUrl)
|
||||
else MatrixItem.RoomItem(roomId, roomName ?: roomAlias, avatarUrl)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ import im.vector.app.databinding.DialogBaseEditTextBinding
|
|||
import im.vector.app.databinding.DialogShareQrCodeBinding
|
||||
import im.vector.app.databinding.FragmentMatrixProfileBinding
|
||||
import im.vector.app.databinding.ViewStubRoomMemberProfileHeaderBinding
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import im.vector.app.features.crypto.verification.VerificationBottomSheet
|
||||
import im.vector.app.features.displayname.getBestName
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
|
@ -88,6 +89,11 @@ class RoomMemberProfileFragment @Inject constructor(
|
|||
|
||||
override fun getMenuRes() = R.menu.vector_room_member_profile
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
analyticsScreenName = Screen.ScreenName.User
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setupToolbar(views.matrixProfileToolbar)
|
||||
|
|
|
@ -44,6 +44,7 @@ import im.vector.app.core.utils.copyToClipboard
|
|||
import im.vector.app.core.utils.startSharePlainTextIntent
|
||||
import im.vector.app.databinding.FragmentMatrixProfileBinding
|
||||
import im.vector.app.databinding.ViewStubRoomProfileHeaderBinding
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.home.room.detail.RoomDetailPendingAction
|
||||
import im.vector.app.features.home.room.detail.RoomDetailPendingActionStore
|
||||
|
@ -88,6 +89,7 @@ class RoomProfileFragment @Inject constructor(
|
|||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
analyticsScreenName = Screen.ScreenName.RoomSettings
|
||||
setFragmentResultListener(MigrateRoomBottomSheet.REQUEST_KEY) { _, bundle ->
|
||||
bundle.getString(MigrateRoomBottomSheet.BUNDLE_KEY_REPLACEMENT_ROOM)?.let { replacementRoomId ->
|
||||
roomDetailPendingActionStore.data = RoomDetailPendingAction.OpenRoom(replacementRoomId, closeCurrentRoom = true)
|
||||
|
|
|
@ -34,6 +34,7 @@ import im.vector.app.core.platform.VectorBaseFragment
|
|||
import im.vector.app.core.utils.saveMedia
|
||||
import im.vector.app.core.utils.shareMedia
|
||||
import im.vector.app.databinding.FragmentRoomUploadsBinding
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.notifications.NotificationUtils
|
||||
import im.vector.app.features.roomprofile.RoomProfileArgs
|
||||
|
@ -54,6 +55,11 @@ class RoomUploadsFragment @Inject constructor(
|
|||
return FragmentRoomUploadsBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
analyticsScreenName = Screen.ScreenName.RoomUploads
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
|
|
|
@ -29,7 +29,9 @@ import im.vector.app.core.error.ErrorFormatter
|
|||
import im.vector.app.core.extensions.singletonEntryPoint
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.core.utils.toast
|
||||
import im.vector.app.features.analytics.VectorAnalytics
|
||||
import im.vector.app.features.analytics.AnalyticsTracker
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import im.vector.app.features.analytics.screen.ScreenEvent
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
|
@ -37,6 +39,18 @@ import reactivecircus.flowbinding.android.view.clicks
|
|||
import timber.log.Timber
|
||||
|
||||
abstract class VectorSettingsBaseFragment : PreferenceFragmentCompat(), MavericksView {
|
||||
/* ==========================================================================================
|
||||
* Analytics
|
||||
* ========================================================================================== */
|
||||
|
||||
protected var analyticsScreenName: Screen.ScreenName? = null
|
||||
private var screenEvent: ScreenEvent? = null
|
||||
|
||||
protected lateinit var analyticsTracker: AnalyticsTracker
|
||||
|
||||
/* ==========================================================================================
|
||||
* Activity
|
||||
* ========================================================================================== */
|
||||
|
||||
val vectorActivity: VectorBaseActivity<*> by lazy {
|
||||
activity as VectorBaseActivity<*>
|
||||
|
@ -47,7 +61,6 @@ abstract class VectorSettingsBaseFragment : PreferenceFragmentCompat(), Maverick
|
|||
// members
|
||||
protected lateinit var session: Session
|
||||
protected lateinit var errorFormatter: ErrorFormatter
|
||||
protected lateinit var analytics: VectorAnalytics
|
||||
|
||||
/* ==========================================================================================
|
||||
* Views
|
||||
|
@ -72,17 +85,23 @@ abstract class VectorSettingsBaseFragment : PreferenceFragmentCompat(), Maverick
|
|||
super.onAttach(context)
|
||||
session = singletonEntryPoint.activeSessionHolder().getActiveSession()
|
||||
errorFormatter = singletonEntryPoint.errorFormatter()
|
||||
analytics = singletonEntryPoint.analytics()
|
||||
analyticsTracker = singletonEntryPoint.analyticsTracker()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
Timber.i("onResume Fragment ${javaClass.simpleName}")
|
||||
screenEvent = analyticsScreenName?.let { ScreenEvent(it) }
|
||||
vectorActivity.supportActionBar?.setTitle(titleRes)
|
||||
// find the view from parent activity
|
||||
mLoadingView = vectorActivity.findViewById(R.id.vector_settings_spinner_views)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
screenEvent?.send(analyticsTracker)
|
||||
}
|
||||
|
||||
abstract fun bindPref()
|
||||
|
||||
abstract var titleRes: Int
|
||||
|
|
|
@ -16,8 +16,10 @@
|
|||
|
||||
package im.vector.app.features.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.preference.VectorPreference
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import javax.inject.Inject
|
||||
|
||||
class VectorSettingsRootFragment @Inject constructor() : VectorSettingsBaseFragment() {
|
||||
|
@ -25,6 +27,11 @@ class VectorSettingsRootFragment @Inject constructor() : VectorSettingsBaseFragm
|
|||
override var titleRes: Int = R.string.title_activity_settings
|
||||
override val preferenceXmlRes = R.xml.vector_settings_root
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
analyticsScreenName = Screen.ScreenName.Settings
|
||||
}
|
||||
|
||||
override fun bindPref() {
|
||||
tintIcons()
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ import im.vector.app.core.utils.copyToClipboard
|
|||
import im.vector.app.core.utils.openFileSelection
|
||||
import im.vector.app.core.utils.toast
|
||||
import im.vector.app.databinding.DialogImportE2eKeysBinding
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import im.vector.app.features.analytics.ui.consent.AnalyticsConsentViewActions
|
||||
import im.vector.app.features.analytics.ui.consent.AnalyticsConsentViewModel
|
||||
import im.vector.app.features.analytics.ui.consent.AnalyticsConsentViewState
|
||||
|
@ -91,6 +92,11 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
|
|||
|
||||
private val analyticsConsentViewModel: AnalyticsConsentViewModel by fragmentViewModel()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
analyticsScreenName = Screen.ScreenName.SettingsSecurity
|
||||
}
|
||||
|
||||
// cryptography
|
||||
private val mCryptographyCategory by lazy {
|
||||
findPreference<PreferenceCategory>(VectorPreferences.SETTINGS_CRYPTOGRAPHY_PREFERENCE_KEY)!!
|
||||
|
|
|
@ -31,6 +31,7 @@ import im.vector.app.core.platform.VectorBaseFragment
|
|||
import im.vector.app.databinding.FragmentDeactivateAccountBinding
|
||||
import im.vector.app.features.MainActivity
|
||||
import im.vector.app.features.MainActivityArgs
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import im.vector.app.features.auth.ReAuthActivity
|
||||
import im.vector.app.features.settings.VectorSettingsActivity
|
||||
import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
|
||||
|
@ -47,7 +48,7 @@ class DeactivateAccountFragment @Inject constructor() : VectorBaseFragment<Fragm
|
|||
private val reAuthActivityResultLauncher = registerStartForActivityResult { activityResult ->
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
when (activityResult.data?.extras?.getString(ReAuthActivity.RESULT_FLOW_TYPE)) {
|
||||
LoginFlowTypes.SSO -> {
|
||||
LoginFlowTypes.SSO -> {
|
||||
viewModel.handle(DeactivateAccountAction.SsoAuthDone)
|
||||
}
|
||||
LoginFlowTypes.PASSWORD -> {
|
||||
|
@ -63,6 +64,11 @@ class DeactivateAccountFragment @Inject constructor() : VectorBaseFragment<Fragm
|
|||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
analyticsScreenName = Screen.ScreenName.DeactivateAccount
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
(activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.deactivate_account_title)
|
||||
|
|
|
@ -16,8 +16,10 @@
|
|||
|
||||
package im.vector.app.features.settings.notifications
|
||||
|
||||
import android.os.Bundle
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.preference.VectorPreferenceCategory
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import org.matrix.android.sdk.api.pushrules.RuleIds
|
||||
|
||||
class VectorSettingsDefaultNotificationPreferenceFragment :
|
||||
|
@ -34,6 +36,11 @@ class VectorSettingsDefaultNotificationPreferenceFragment :
|
|||
"SETTINGS_PUSH_RULE_MESSAGES_IN_E2E_GROUP_CHAT_PREFERENCE_KEY" to RuleIds.RULE_ID_ENCRYPTED
|
||||
)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
analyticsScreenName = Screen.ScreenName.SettingsDefaultNotifications
|
||||
}
|
||||
|
||||
override fun bindPref() {
|
||||
super.bindPref()
|
||||
val category = findPreference<VectorPreferenceCategory>("SETTINGS_DEFAULT")!!
|
||||
|
|
|
@ -25,6 +25,7 @@ import im.vector.app.core.preference.KeywordPreference
|
|||
import im.vector.app.core.preference.VectorCheckboxPreference
|
||||
import im.vector.app.core.preference.VectorPreference
|
||||
import im.vector.app.core.preference.VectorPreferenceCategory
|
||||
import im.vector.app.features.analytics.plan.Screen
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
@ -34,7 +35,7 @@ import org.matrix.android.sdk.api.pushrules.rest.PushRule
|
|||
import org.matrix.android.sdk.api.pushrules.toJson
|
||||
|
||||
class VectorSettingsKeywordAndMentionsNotificationPreferenceFragment :
|
||||
VectorSettingsPushRuleNotificationPreferenceFragment() {
|
||||
VectorSettingsPushRuleNotificationPreferenceFragment() {
|
||||
|
||||
override var titleRes: Int = R.string.settings_notification_mentions_and_keywords
|
||||
|
||||
|
@ -42,6 +43,11 @@ class VectorSettingsKeywordAndMentionsNotificationPreferenceFragment :
|
|||
|
||||
private var keywordsHasFocus = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
analyticsScreenName = Screen.ScreenName.SettingsMentionsAndKeywords
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
session.getKeywords().observe(viewLifecycleOwner, this::updateWithKeywords)
|
||||
|
@ -71,7 +77,7 @@ class VectorSettingsKeywordAndMentionsNotificationPreferenceFragment :
|
|||
val keywords = editKeywordPreference.keywords
|
||||
val newChecked = newValue as Boolean
|
||||
displayLoadingView()
|
||||
updateKeywordPushRules(keywords, newChecked) { result ->
|
||||
updateKeywordPushRules(keywords, newChecked) { result ->
|
||||
hideLoadingView()
|
||||
if (!isAdded) {
|
||||
return@updateKeywordPushRules
|
||||
|
@ -88,7 +94,7 @@ class VectorSettingsKeywordAndMentionsNotificationPreferenceFragment :
|
|||
false
|
||||
}
|
||||
|
||||
editKeywordPreference.listener = object : KeywordPreference.Listener {
|
||||
editKeywordPreference.listener = object : KeywordPreference.Listener {
|
||||
override fun onFocusDidChange(hasFocus: Boolean) {
|
||||
keywordsHasFocus = true
|
||||
}
|
||||
|
@ -174,8 +180,8 @@ class VectorSettingsKeywordAndMentionsNotificationPreferenceFragment :
|
|||
}
|
||||
|
||||
override val prefKeyToPushRuleId = mapOf(
|
||||
"SETTINGS_PUSH_RULE_CONTAINING_MY_DISPLAY_NAME_PREFERENCE_KEY" to RuleIds.RULE_ID_CONTAIN_DISPLAY_NAME,
|
||||
"SETTINGS_PUSH_RULE_CONTAINING_MY_USER_NAME_PREFERENCE_KEY" to RuleIds.RULE_ID_CONTAIN_USER_NAME,
|
||||
"SETTINGS_PUSH_RULE_MESSAGES_CONTAINING_AT_ROOM_PREFERENCE_KEY" to RuleIds.RULE_ID_ROOM_NOTIF
|
||||
)
|
||||
"SETTINGS_PUSH_RULE_CONTAINING_MY_DISPLAY_NAME_PREFERENCE_KEY" to RuleIds.RULE_ID_CONTAIN_DISPLAY_NAME,
|
||||
"SETTINGS_PUSH_RULE_CONTAINING_MY_USER_NAME_PREFERENCE_KEY" to RuleIds.RULE_ID_CONTAIN_USER_NAME,
|
||||
"SETTINGS_PUSH_RULE_MESSAGES_CONTAINING_AT_ROOM_PREFERENCE_KEY" to RuleIds.RULE_ID_ROOM_NOTIF
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue