mirror of
https://github.com/element-hq/element-android
synced 2024-11-27 20:06:51 +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
|
# 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
|
### 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
|
### Do not import temporary legacy classes
|
||||||
import org.matrix.android.sdk.internal.legacy.riot===3
|
import org.matrix.android.sdk.internal.legacy.riot===3
|
||||||
|
|
|
@ -21,7 +21,7 @@ import dagger.hilt.InstallIn
|
||||||
import dagger.hilt.components.SingletonComponent
|
import dagger.hilt.components.SingletonComponent
|
||||||
import im.vector.app.core.dialogs.UnrecognizedCertificateDialog
|
import im.vector.app.core.dialogs.UnrecognizedCertificateDialog
|
||||||
import im.vector.app.core.error.ErrorFormatter
|
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.call.webrtc.WebRtcCallManager
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
import im.vector.app.features.navigation.Navigator
|
import im.vector.app.features.navigation.Navigator
|
||||||
|
@ -56,7 +56,7 @@ interface SingletonEntryPoint {
|
||||||
|
|
||||||
fun pinLocker(): PinLocker
|
fun pinLocker(): PinLocker
|
||||||
|
|
||||||
fun analytics(): VectorAnalytics
|
fun analyticsTracker(): AnalyticsTracker
|
||||||
|
|
||||||
fun webRtcCallManager(): WebRtcCallManager
|
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.error.ErrorFormatter
|
||||||
import im.vector.app.core.time.Clock
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.core.time.DefaultClock
|
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.VectorAnalytics
|
||||||
import im.vector.app.features.analytics.impl.DefaultVectorAnalytics
|
import im.vector.app.features.analytics.impl.DefaultVectorAnalytics
|
||||||
import im.vector.app.features.invite.AutoAcceptInvites
|
import im.vector.app.features.invite.AutoAcceptInvites
|
||||||
|
@ -64,6 +65,9 @@ abstract class VectorBindModule {
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindVectorAnalytics(analytics: DefaultVectorAnalytics): VectorAnalytics
|
abstract fun bindVectorAnalytics(analytics: DefaultVectorAnalytics): VectorAnalytics
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun bindAnalyticsTracker(analytics: DefaultVectorAnalytics): AnalyticsTracker
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindErrorFormatter(formatter: DefaultErrorFormatter): ErrorFormatter
|
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.core.utils.toast
|
||||||
import im.vector.app.features.MainActivity
|
import im.vector.app.features.MainActivity
|
||||||
import im.vector.app.features.MainActivityArgs
|
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.configuration.VectorConfiguration
|
||||||
import im.vector.app.features.consent.ConsentNotGivenHelper
|
import im.vector.app.features.consent.ConsentNotGivenHelper
|
||||||
import im.vector.app.features.navigation.Navigator
|
import im.vector.app.features.navigation.Navigator
|
||||||
|
@ -90,6 +92,15 @@ import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), MavericksView {
|
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
|
* View
|
||||||
* ========================================================================================== */
|
* ========================================================================================== */
|
||||||
|
@ -133,7 +144,6 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
|
||||||
private lateinit var sessionListener: SessionListener
|
private lateinit var sessionListener: SessionListener
|
||||||
protected lateinit var bugReporter: BugReporter
|
protected lateinit var bugReporter: BugReporter
|
||||||
private lateinit var pinLocker: PinLocker
|
private lateinit var pinLocker: PinLocker
|
||||||
protected lateinit var analytics: VectorAnalytics
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var rageShake: RageShake
|
lateinit var rageShake: RageShake
|
||||||
|
@ -189,7 +199,7 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
|
||||||
configurationViewModel = viewModelProvider.get(ConfigurationViewModel::class.java)
|
configurationViewModel = viewModelProvider.get(ConfigurationViewModel::class.java)
|
||||||
bugReporter = singletonEntryPoint.bugReporter()
|
bugReporter = singletonEntryPoint.bugReporter()
|
||||||
pinLocker = singletonEntryPoint.pinLocker()
|
pinLocker = singletonEntryPoint.pinLocker()
|
||||||
analytics = singletonEntryPoint.analytics()
|
analyticsTracker = singletonEntryPoint.analyticsTracker()
|
||||||
navigator = singletonEntryPoint.navigator()
|
navigator = singletonEntryPoint.navigator()
|
||||||
activeSessionHolder = singletonEntryPoint.activeSessionHolder()
|
activeSessionHolder = singletonEntryPoint.activeSessionHolder()
|
||||||
vectorPreferences = singletonEntryPoint.vectorPreferences()
|
vectorPreferences = singletonEntryPoint.vectorPreferences()
|
||||||
|
@ -324,7 +334,7 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
Timber.i("onResume Activity ${javaClass.simpleName}")
|
Timber.i("onResume Activity ${javaClass.simpleName}")
|
||||||
|
screenEvent = analyticsScreenName?.let { ScreenEvent(it) }
|
||||||
configurationViewModel.onActivityResumed()
|
configurationViewModel.onActivityResumed()
|
||||||
|
|
||||||
if (this !is BugReportActivity && vectorPreferences.useRageshake()) {
|
if (this !is BugReportActivity && vectorPreferences.useRageshake()) {
|
||||||
|
@ -363,6 +373,7 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
|
screenEvent?.send(analyticsTracker, analyticsScreenName)
|
||||||
Timber.i("onPause Activity ${javaClass.simpleName}")
|
Timber.i("onPause Activity ${javaClass.simpleName}")
|
||||||
|
|
||||||
rageShake.stop()
|
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.singletonEntryPoint
|
||||||
import im.vector.app.core.extensions.toMvRxBundle
|
import im.vector.app.core.extensions.toMvRxBundle
|
||||||
import im.vector.app.core.utils.DimensionConverter
|
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.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import reactivecircus.flowbinding.android.view.clicks
|
import reactivecircus.flowbinding.android.view.clicks
|
||||||
|
@ -47,6 +49,14 @@ import timber.log.Timber
|
||||||
* Add Mavericks capabilities, handle DI and bindings.
|
* Add Mavericks capabilities, handle DI and bindings.
|
||||||
*/
|
*/
|
||||||
abstract class VectorBaseBottomSheetDialogFragment<VB : ViewBinding> : BottomSheetDialogFragment(), MavericksView {
|
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
|
* View
|
||||||
|
@ -84,8 +94,6 @@ abstract class VectorBaseBottomSheetDialogFragment<VB : ViewBinding> : BottomShe
|
||||||
|
|
||||||
open val showExpanded = false
|
open val showExpanded = false
|
||||||
|
|
||||||
protected lateinit var analytics: VectorAnalytics
|
|
||||||
|
|
||||||
interface ResultListener {
|
interface ResultListener {
|
||||||
fun onBottomSheetResult(resultCode: Int, data: Any?)
|
fun onBottomSheetResult(resultCode: Int, data: Any?)
|
||||||
|
|
||||||
|
@ -124,13 +132,19 @@ abstract class VectorBaseBottomSheetDialogFragment<VB : ViewBinding> : BottomShe
|
||||||
val activityEntryPoint = EntryPointAccessors.fromActivity(vectorBaseActivity, ActivityEntryPoint::class.java)
|
val activityEntryPoint = EntryPointAccessors.fromActivity(vectorBaseActivity, ActivityEntryPoint::class.java)
|
||||||
viewModelFactory = activityEntryPoint.viewModelFactory()
|
viewModelFactory = activityEntryPoint.viewModelFactory()
|
||||||
val singletonEntryPoint = context.singletonEntryPoint()
|
val singletonEntryPoint = context.singletonEntryPoint()
|
||||||
analytics = singletonEntryPoint.analytics()
|
analyticsTracker = singletonEntryPoint.analyticsTracker()
|
||||||
super.onAttach(context)
|
super.onAttach(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
Timber.i("onResume BottomSheet ${javaClass.simpleName}")
|
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 {
|
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.error.ErrorFormatter
|
||||||
import im.vector.app.core.extensions.singletonEntryPoint
|
import im.vector.app.core.extensions.singletonEntryPoint
|
||||||
import im.vector.app.core.extensions.toMvRxBundle
|
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.app.features.navigation.Navigator
|
||||||
import im.vector.lib.ui.styles.dialogs.MaterialProgressDialog
|
import im.vector.lib.ui.styles.dialogs.MaterialProgressDialog
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
@ -51,6 +53,18 @@ import reactivecircus.flowbinding.android.view.clicks
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
abstract class VectorBaseFragment<VB : ViewBinding> : Fragment(), MavericksView {
|
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 {
|
protected val vectorBaseActivity: VectorBaseActivity<*> by lazy {
|
||||||
activity as VectorBaseActivity<*>
|
activity as VectorBaseActivity<*>
|
||||||
|
@ -61,7 +75,6 @@ abstract class VectorBaseFragment<VB : ViewBinding> : Fragment(), MavericksView
|
||||||
* ========================================================================================== */
|
* ========================================================================================== */
|
||||||
|
|
||||||
protected lateinit var navigator: Navigator
|
protected lateinit var navigator: Navigator
|
||||||
protected lateinit var analytics: VectorAnalytics
|
|
||||||
protected lateinit var errorFormatter: ErrorFormatter
|
protected lateinit var errorFormatter: ErrorFormatter
|
||||||
protected lateinit var unrecognizedCertificateDialog: UnrecognizedCertificateDialog
|
protected lateinit var unrecognizedCertificateDialog: UnrecognizedCertificateDialog
|
||||||
|
|
||||||
|
@ -98,7 +111,7 @@ abstract class VectorBaseFragment<VB : ViewBinding> : Fragment(), MavericksView
|
||||||
val activityEntryPoint = EntryPointAccessors.fromActivity(vectorBaseActivity, ActivityEntryPoint::class.java)
|
val activityEntryPoint = EntryPointAccessors.fromActivity(vectorBaseActivity, ActivityEntryPoint::class.java)
|
||||||
navigator = singletonEntryPoint.navigator()
|
navigator = singletonEntryPoint.navigator()
|
||||||
errorFormatter = singletonEntryPoint.errorFormatter()
|
errorFormatter = singletonEntryPoint.errorFormatter()
|
||||||
analytics = singletonEntryPoint.analytics()
|
analyticsTracker = singletonEntryPoint.analyticsTracker()
|
||||||
unrecognizedCertificateDialog = singletonEntryPoint.unrecognizedCertificateDialog()
|
unrecognizedCertificateDialog = singletonEntryPoint.unrecognizedCertificateDialog()
|
||||||
viewModelFactory = activityEntryPoint.viewModelFactory()
|
viewModelFactory = activityEntryPoint.viewModelFactory()
|
||||||
childFragmentManager.fragmentFactory = activityEntryPoint.fragmentFactory()
|
childFragmentManager.fragmentFactory = activityEntryPoint.fragmentFactory()
|
||||||
|
@ -125,12 +138,14 @@ abstract class VectorBaseFragment<VB : ViewBinding> : Fragment(), MavericksView
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
Timber.i("onResume Fragment ${javaClass.simpleName}")
|
Timber.i("onResume Fragment ${javaClass.simpleName}")
|
||||||
|
screenEvent = analyticsScreenName?.let { ScreenEvent(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
Timber.i("onPause Fragment ${javaClass.simpleName}")
|
Timber.i("onPause Fragment ${javaClass.simpleName}")
|
||||||
|
screenEvent?.send(analyticsTracker)
|
||||||
}
|
}
|
||||||
|
|
||||||
@CallSuper
|
@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
|
@Singleton
|
||||||
class DecryptionFailureTracker @Inject constructor(
|
class DecryptionFailureTracker @Inject constructor(
|
||||||
private val vectorAnalytics: VectorAnalytics,
|
private val analyticsTracker: AnalyticsTracker,
|
||||||
private val clock: Clock
|
private val clock: Clock
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ class DecryptionFailureTracker @Inject constructor(
|
||||||
// for now we ignore events already reported even if displayed again?
|
// for now we ignore events already reported even if displayed again?
|
||||||
.filter { alreadyReported.contains(it).not() }
|
.filter { alreadyReported.contains(it).not() }
|
||||||
.forEach { failedEventId ->
|
.forEach { failedEventId ->
|
||||||
vectorAnalytics.capture(Error(failedEventId, Error.Domain.E2EE, aggregation.key))
|
analyticsTracker.capture(Error(failedEventId, Error.Domain.E2EE, aggregation.key))
|
||||||
alreadyReported.add(failedEventId)
|
alreadyReported.add(failedEventId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,11 +16,9 @@
|
||||||
|
|
||||||
package im.vector.app.features.analytics
|
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
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
interface VectorAnalytics {
|
interface VectorAnalytics : AnalyticsTracker {
|
||||||
/**
|
/**
|
||||||
* Return a Flow of Boolean, true if the user has given their consent
|
* 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
|
* To be called when application is started
|
||||||
*/
|
*/
|
||||||
fun init()
|
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.
|
* Triggered when a call has ended.
|
||||||
*/
|
*/
|
||||||
data class CallEnded(
|
data class CallEnded(
|
||||||
/**
|
/**
|
||||||
* The duration of the call in milliseconds.
|
* The duration of the call in milliseconds.
|
||||||
*/
|
*/
|
||||||
val durationMs: Int,
|
val durationMs: Int,
|
||||||
/**
|
/**
|
||||||
* Whether its a video call or not.
|
* Whether its a video call or not.
|
||||||
*/
|
*/
|
||||||
val isVideo: Boolean,
|
val isVideo: Boolean,
|
||||||
/**
|
/**
|
||||||
* Number of participants in the call.
|
* Number of participants in the call.
|
||||||
*/
|
*/
|
||||||
val numParticipants: Int,
|
val numParticipants: Int,
|
||||||
/**
|
/**
|
||||||
* Whether this user placed it.
|
* Whether this user placed it.
|
||||||
*/
|
*/
|
||||||
val placed: Boolean,
|
val placed: Boolean,
|
||||||
) : VectorAnalyticsEvent {
|
) : VectorAnalyticsEvent {
|
||||||
|
|
||||||
override fun getName() = "CallEnded"
|
override fun getName() = "CallEnded"
|
||||||
|
|
|
@ -25,18 +25,18 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
|
||||||
* Triggered when an error occurred in a call.
|
* Triggered when an error occurred in a call.
|
||||||
*/
|
*/
|
||||||
data class CallError(
|
data class CallError(
|
||||||
/**
|
/**
|
||||||
* Whether its a video call or not.
|
* Whether its a video call or not.
|
||||||
*/
|
*/
|
||||||
val isVideo: Boolean,
|
val isVideo: Boolean,
|
||||||
/**
|
/**
|
||||||
* Number of participants in the call.
|
* Number of participants in the call.
|
||||||
*/
|
*/
|
||||||
val numParticipants: Int,
|
val numParticipants: Int,
|
||||||
/**
|
/**
|
||||||
* Whether this user placed it.
|
* Whether this user placed it.
|
||||||
*/
|
*/
|
||||||
val placed: Boolean,
|
val placed: Boolean,
|
||||||
) : VectorAnalyticsEvent {
|
) : VectorAnalyticsEvent {
|
||||||
|
|
||||||
override fun getName() = "CallError"
|
override fun getName() = "CallError"
|
||||||
|
|
|
@ -25,18 +25,18 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
|
||||||
* Triggered when a call is started.
|
* Triggered when a call is started.
|
||||||
*/
|
*/
|
||||||
data class CallStarted(
|
data class CallStarted(
|
||||||
/**
|
/**
|
||||||
* Whether its a video call or not.
|
* Whether its a video call or not.
|
||||||
*/
|
*/
|
||||||
val isVideo: Boolean,
|
val isVideo: Boolean,
|
||||||
/**
|
/**
|
||||||
* Number of participants in the call.
|
* Number of participants in the call.
|
||||||
*/
|
*/
|
||||||
val numParticipants: Int,
|
val numParticipants: Int,
|
||||||
/**
|
/**
|
||||||
* Whether this user placed it.
|
* Whether this user placed it.
|
||||||
*/
|
*/
|
||||||
val placed: Boolean,
|
val placed: Boolean,
|
||||||
) : VectorAnalyticsEvent {
|
) : VectorAnalyticsEvent {
|
||||||
|
|
||||||
override fun getName() = "CallStarted"
|
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.
|
* Triggered when the user clicks/taps on a UI element.
|
||||||
*/
|
*/
|
||||||
data class Click(
|
data class Click(
|
||||||
/**
|
/**
|
||||||
* The index of the element, if its in a list of elements.
|
* The index of the element, if its in a list of elements.
|
||||||
*/
|
*/
|
||||||
val index: Int? = null,
|
val index: Int? = null,
|
||||||
/**
|
/**
|
||||||
* The unique name of this element.
|
* The unique name of this element.
|
||||||
*/
|
*/
|
||||||
val name: Name,
|
val name: Name,
|
||||||
) : VectorAnalyticsEvent {
|
) : VectorAnalyticsEvent {
|
||||||
|
|
||||||
enum class Name {
|
enum class Name {
|
||||||
|
|
|
@ -25,10 +25,10 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
|
||||||
* Triggered when the user creates a room.
|
* Triggered when the user creates a room.
|
||||||
*/
|
*/
|
||||||
data class CreatedRoom(
|
data class CreatedRoom(
|
||||||
/**
|
/**
|
||||||
* Whether the room is a DM.
|
* Whether the room is a DM.
|
||||||
*/
|
*/
|
||||||
val isDM: Boolean,
|
val isDM: Boolean,
|
||||||
) : VectorAnalyticsEvent {
|
) : VectorAnalyticsEvent {
|
||||||
|
|
||||||
override fun getName() = "CreatedRoom"
|
override fun getName() = "CreatedRoom"
|
||||||
|
|
|
@ -25,12 +25,12 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
|
||||||
* Triggered when an error occurred
|
* Triggered when an error occurred
|
||||||
*/
|
*/
|
||||||
data class Error(
|
data class Error(
|
||||||
/**
|
/**
|
||||||
* Context - client defined, can be used for debugging
|
* Context - client defined, can be used for debugging
|
||||||
*/
|
*/
|
||||||
val context: String? = null,
|
val context: String? = null,
|
||||||
val domain: Domain,
|
val domain: Domain,
|
||||||
val name: Name,
|
val name: Name,
|
||||||
) : VectorAnalyticsEvent {
|
) : VectorAnalyticsEvent {
|
||||||
|
|
||||||
enum class Domain {
|
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.
|
* Triggered when the user joins a room.
|
||||||
*/
|
*/
|
||||||
data class JoinedRoom(
|
data class JoinedRoom(
|
||||||
/**
|
/**
|
||||||
* Whether the room is a DM.
|
* Whether the room is a DM.
|
||||||
*/
|
*/
|
||||||
val isDM: Boolean,
|
val isDM: Boolean,
|
||||||
/**
|
/**
|
||||||
* The size of the room.
|
* The size of the room.
|
||||||
*/
|
*/
|
||||||
val roomSize: RoomSize,
|
val roomSize: RoomSize,
|
||||||
) : VectorAnalyticsEvent {
|
) : VectorAnalyticsEvent {
|
||||||
|
|
||||||
enum class RoomSize {
|
enum class RoomSize {
|
||||||
|
|
|
@ -25,22 +25,23 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
|
||||||
* Triggered after timing an operation in the app.
|
* Triggered after timing an operation in the app.
|
||||||
*/
|
*/
|
||||||
data class PerformanceTimer(
|
data class PerformanceTimer(
|
||||||
/**
|
/**
|
||||||
* Client defined, can be used for debugging.
|
* Client defined, can be used for debugging.
|
||||||
*/
|
*/
|
||||||
val context: String? = null,
|
val context: String? = null,
|
||||||
/**
|
/**
|
||||||
* Client defined, an optional value to indicate how many items were handled during the operation.
|
* Client defined, an optional value to indicate how many items were
|
||||||
*/
|
* handled during the operation.
|
||||||
val itemCount: Int? = null,
|
*/
|
||||||
/**
|
val itemCount: Int? = null,
|
||||||
* The timer that is being reported.
|
/**
|
||||||
*/
|
* The timer that is being reported.
|
||||||
val name: Name,
|
*/
|
||||||
/**
|
val name: Name,
|
||||||
* The time reported by the timer in milliseconds.
|
/**
|
||||||
*/
|
* The time reported by the timer in milliseconds.
|
||||||
val timeMs: Int,
|
*/
|
||||||
|
val timeMs: Int,
|
||||||
) : VectorAnalyticsEvent {
|
) : VectorAnalyticsEvent {
|
||||||
|
|
||||||
enum class Name {
|
enum class Name {
|
||||||
|
@ -55,7 +56,8 @@ data class PerformanceTimer(
|
||||||
InitialSyncRequest,
|
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,
|
NotificationsOpenEvent,
|
||||||
|
|
||||||
|
@ -65,7 +67,8 @@ data class PerformanceTimer(
|
||||||
StartupIncrementalSync,
|
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,
|
StartupInitialSync,
|
||||||
|
|
||||||
|
@ -80,7 +83,8 @@ data class PerformanceTimer(
|
||||||
StartupStorePreload,
|
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,
|
StartupStoreReady,
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,28 +25,221 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsScreen
|
||||||
* Triggered when the user changed screen
|
* Triggered when the user changed screen
|
||||||
*/
|
*/
|
||||||
data class Screen(
|
data class Screen(
|
||||||
/**
|
/**
|
||||||
* How long the screen was displayed for in milliseconds.
|
* How long the screen was displayed for in milliseconds.
|
||||||
*/
|
*/
|
||||||
val durationMs: Int? = null,
|
val durationMs: Int? = null,
|
||||||
val screenName: ScreenName,
|
val screenName: ScreenName,
|
||||||
) : VectorAnalyticsScreen {
|
) : VectorAnalyticsScreen {
|
||||||
|
|
||||||
enum class ScreenName {
|
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,
|
Group,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Home tab on iOS | possibly the same on Android? | The Home space
|
||||||
|
* on Web?
|
||||||
|
*/
|
||||||
Home,
|
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,
|
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,
|
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,
|
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,
|
User,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ?
|
||||||
|
*/
|
||||||
WebCompleteSecurity,
|
WebCompleteSecurity,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ?
|
||||||
|
*/
|
||||||
WebE2ESetup,
|
WebE2ESetup,
|
||||||
WebForgotPassword,
|
|
||||||
|
/**
|
||||||
|
* ?
|
||||||
|
*/
|
||||||
WebLoading,
|
WebLoading,
|
||||||
WebLogin,
|
|
||||||
WebRegister,
|
/**
|
||||||
|
* ?
|
||||||
|
*/
|
||||||
WebSoftLogout,
|
WebSoftLogout,
|
||||||
WebWelcome,
|
|
||||||
|
/**
|
||||||
|
* The splash screen.
|
||||||
|
*/
|
||||||
|
Welcome,
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getName() = screenName.name
|
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
|
package im.vector.app.features.call.dialpad
|
||||||
|
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
|
import android.content.Context
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.telephony.PhoneNumberFormattingTextWatcher
|
import android.telephony.PhoneNumberFormattingTextWatcher
|
||||||
|
@ -37,6 +38,10 @@ import androidx.fragment.app.Fragment
|
||||||
import com.android.dialer.dialpadview.DialpadView
|
import com.android.dialer.dialpadview.DialpadView
|
||||||
import com.android.dialer.dialpadview.DigitsEditText
|
import com.android.dialer.dialpadview.DigitsEditText
|
||||||
import im.vector.app.R
|
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
|
import im.vector.app.features.themes.ThemeUtils
|
||||||
|
|
||||||
class DialPadFragment : Fragment(), TextWatcher {
|
class DialPadFragment : Fragment(), TextWatcher {
|
||||||
|
@ -53,6 +58,25 @@ class DialPadFragment : Fragment(), TextWatcher {
|
||||||
private var enableDelete = true
|
private var enableDelete = true
|
||||||
private var enableFabOk = 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(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
|
|
|
@ -270,6 +270,10 @@ class WebRtcCall(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun durationMillis(): Int {
|
||||||
|
return timer.elapsedTime().toInt()
|
||||||
|
}
|
||||||
|
|
||||||
fun formattedDuration(): String {
|
fun formattedDuration(): String {
|
||||||
return formatDuration(
|
return formatDuration(
|
||||||
Duration.ofMillis(timer.elapsedTime())
|
Duration.ofMillis(timer.elapsedTime())
|
||||||
|
|
|
@ -22,6 +22,9 @@ import androidx.lifecycle.LifecycleOwner
|
||||||
import im.vector.app.ActiveSessionDataSource
|
import im.vector.app.ActiveSessionDataSource
|
||||||
import im.vector.app.BuildConfig
|
import im.vector.app.BuildConfig
|
||||||
import im.vector.app.core.services.CallService
|
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.VectorCallActivity
|
||||||
import im.vector.app.features.call.audio.CallAudioManager
|
import im.vector.app.features.call.audio.CallAudioManager
|
||||||
import im.vector.app.features.call.lookup.CallProtocolsChecker
|
import im.vector.app.features.call.lookup.CallProtocolsChecker
|
||||||
|
@ -68,7 +71,8 @@ private val loggerTag = LoggerTag("WebRtcCallManager", LoggerTag.VOIP)
|
||||||
@Singleton
|
@Singleton
|
||||||
class WebRtcCallManager @Inject constructor(
|
class WebRtcCallManager @Inject constructor(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val activeSessionDataSource: ActiveSessionDataSource
|
private val activeSessionDataSource: ActiveSessionDataSource,
|
||||||
|
private val analyticsTracker: AnalyticsTracker
|
||||||
) : CallListener,
|
) : CallListener,
|
||||||
DefaultLifecycleObserver {
|
DefaultLifecycleObserver {
|
||||||
|
|
||||||
|
@ -237,6 +241,7 @@ class WebRtcCallManager @Inject constructor(
|
||||||
val currentCall = getCurrentCall().takeIf { it != call }
|
val currentCall = getCurrentCall().takeIf { it != call }
|
||||||
currentCall?.updateRemoteOnHold(onHold = true)
|
currentCall?.updateRemoteOnHold(onHold = true)
|
||||||
audioManager.setMode(if (call.mxCall.isVideoCall) CallAudioManager.Mode.VIDEO_CALL else CallAudioManager.Mode.AUDIO_CALL)
|
audioManager.setMode(if (call.mxCall.isVideoCall) CallAudioManager.Mode.VIDEO_CALL else CallAudioManager.Mode.AUDIO_CALL)
|
||||||
|
call.trackCallStarted()
|
||||||
this.currentCall.setAndNotify(call)
|
this.currentCall.setAndNotify(call)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,6 +250,7 @@ class WebRtcCallManager @Inject constructor(
|
||||||
val webRtcCall = callsByCallId.remove(callId) ?: return Unit.also {
|
val webRtcCall = callsByCallId.remove(callId) ?: return Unit.also {
|
||||||
Timber.tag(loggerTag.value).v("On call ended for unknown call $callId")
|
Timber.tag(loggerTag.value).v("On call ended for unknown call $callId")
|
||||||
}
|
}
|
||||||
|
webRtcCall.trackCallEnded()
|
||||||
CallService.onCallTerminated(context, callId, endCallReason, rejected)
|
CallService.onCallTerminated(context, callId, endCallReason, rejected)
|
||||||
callsByRoomId[webRtcCall.signalingRoomId]?.remove(webRtcCall)
|
callsByRoomId[webRtcCall.signalingRoomId]?.remove(webRtcCall)
|
||||||
callsByRoomId[webRtcCall.nativeRoomId]?.remove(webRtcCall)
|
callsByRoomId[webRtcCall.nativeRoomId]?.remove(webRtcCall)
|
||||||
|
@ -443,4 +449,28 @@ class WebRtcCallManager @Inject constructor(
|
||||||
}
|
}
|
||||||
call.onCallAssertedIdentityReceived(callAssertedIdentityContent)
|
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.checkPermissions
|
||||||
import im.vector.app.core.utils.onPermissionDeniedSnackbar
|
import im.vector.app.core.utils.onPermissionDeniedSnackbar
|
||||||
import im.vector.app.core.utils.registerForPermissionsResult
|
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.contactsbook.ContactsBookFragment
|
||||||
import im.vector.app.features.userdirectory.UserListFragment
|
import im.vector.app.features.userdirectory.UserListFragment
|
||||||
import im.vector.app.features.userdirectory.UserListFragmentArgs
|
import im.vector.app.features.userdirectory.UserListFragmentArgs
|
||||||
|
@ -63,6 +64,7 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() {
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
analyticsScreenName = Screen.ScreenName.StartChat
|
||||||
views.toolbar.visibility = View.GONE
|
views.toolbar.visibility = View.GONE
|
||||||
|
|
||||||
sharedActionViewModel = viewModelProvider.get(UserListSharedActionViewModel::class.java)
|
sharedActionViewModel = viewModelProvider.get(UserListSharedActionViewModel::class.java)
|
||||||
|
|
|
@ -24,6 +24,7 @@ import android.os.Bundle
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
import androidx.core.view.GravityCompat
|
import androidx.core.view.GravityCompat
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.drawerlayout.widget.DrawerLayout
|
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.MainActivity
|
||||||
import im.vector.app.features.MainActivityArgs
|
import im.vector.app.features.MainActivityArgs
|
||||||
import im.vector.app.features.analytics.accountdata.AnalyticsAccountDataViewModel
|
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.disclaimer.showDisclaimerDialog
|
||||||
import im.vector.app.features.matrixto.MatrixToBottomSheet
|
import im.vector.app.features.matrixto.MatrixToBottomSheet
|
||||||
import im.vector.app.features.navigation.Navigator
|
import im.vector.app.features.navigation.Navigator
|
||||||
|
@ -104,6 +107,7 @@ class HomeActivity :
|
||||||
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
|
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
|
||||||
|
|
||||||
private val homeActivityViewModel: HomeActivityViewModel by viewModel()
|
private val homeActivityViewModel: HomeActivityViewModel by viewModel()
|
||||||
|
|
||||||
@Suppress("UNUSED")
|
@Suppress("UNUSED")
|
||||||
private val analyticsAccountDataViewModel: AnalyticsAccountDataViewModel by viewModel()
|
private val analyticsAccountDataViewModel: AnalyticsAccountDataViewModel by viewModel()
|
||||||
@Suppress("UNUSED")
|
@Suppress("UNUSED")
|
||||||
|
@ -164,6 +168,16 @@ class HomeActivity :
|
||||||
}
|
}
|
||||||
|
|
||||||
private val drawerListener = object : DrawerLayout.SimpleDrawerListener() {
|
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) {
|
override fun onDrawerStateChanged(newState: Int) {
|
||||||
hideKeyboard()
|
hideKeyboard()
|
||||||
}
|
}
|
||||||
|
@ -175,6 +189,7 @@ class HomeActivity :
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
analyticsScreenName = Screen.ScreenName.Home
|
||||||
supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, false)
|
supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, false)
|
||||||
FcmHelper.ensureFcmTokenIsRetrieved(this, pushManager, vectorPreferences.areNotificationEnabledForDevice())
|
FcmHelper.ensureFcmTokenIsRetrieved(this, pushManager, vectorPreferences.areNotificationEnabledForDevice())
|
||||||
sharedActionViewModel = viewModelProvider.get(HomeSharedActionViewModel::class.java)
|
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.platform.VectorBaseFragment
|
||||||
import im.vector.app.core.utils.startSharePlainTextIntent
|
import im.vector.app.core.utils.startSharePlainTextIntent
|
||||||
import im.vector.app.databinding.FragmentHomeDrawerBinding
|
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.VectorPreferences
|
||||||
import im.vector.app.features.settings.VectorSettingsActivity
|
import im.vector.app.features.settings.VectorSettingsActivity
|
||||||
import im.vector.app.features.spaces.SpaceListFragment
|
import im.vector.app.features.spaces.SpaceListFragment
|
||||||
|
@ -97,6 +98,7 @@ class HomeDrawerFragment @Inject constructor(
|
||||||
|
|
||||||
views.homeDrawerInviteFriendButton.debouncedClicks {
|
views.homeDrawerInviteFriendButton.debouncedClicks {
|
||||||
session.permalinkService().createPermalink(sharedActionViewModel.session.myUserId)?.let { permalink ->
|
session.permalinkService().createPermalink(sharedActionViewModel.session.myUserId)?.let { permalink ->
|
||||||
|
analyticsTracker.screen(Screen(screenName = Screen.ScreenName.MobileInviteFriends))
|
||||||
val text = getString(R.string.invite_friends_text, permalink)
|
val text = getString(R.string.invite_friends_text, permalink)
|
||||||
|
|
||||||
startSharePlainTextIntent(
|
startSharePlainTextIntent(
|
||||||
|
|
|
@ -19,6 +19,7 @@ package im.vector.app.features.home.room.detail
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.view.GravityCompat
|
import androidx.core.view.GravityCompat
|
||||||
import androidx.drawerlayout.widget.DrawerLayout
|
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.ToolbarConfigurable
|
||||||
import im.vector.app.core.platform.VectorBaseActivity
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
import im.vector.app.databinding.ActivityRoomDetailBinding
|
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.breadcrumbs.BreadcrumbsFragment
|
||||||
import im.vector.app.features.home.room.detail.timeline.helper.VoiceMessagePlaybackTracker
|
import im.vector.app.features.home.room.detail.timeline.helper.VoiceMessagePlaybackTracker
|
||||||
import im.vector.app.features.matrixto.MatrixToBottomSheet
|
import im.vector.app.features.matrixto.MatrixToBottomSheet
|
||||||
|
@ -161,6 +164,16 @@ class RoomDetailActivity :
|
||||||
}
|
}
|
||||||
|
|
||||||
private val drawerListener = object : DrawerLayout.SimpleDrawerListener() {
|
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) {
|
override fun onDrawerStateChanged(newState: Int) {
|
||||||
hideKeyboard()
|
hideKeyboard()
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,8 @@ import im.vector.app.core.utils.startInstallFromSourceIntent
|
||||||
import im.vector.app.core.utils.toast
|
import im.vector.app.core.utils.toast
|
||||||
import im.vector.app.databinding.DialogReportContentBinding
|
import im.vector.app.databinding.DialogReportContentBinding
|
||||||
import im.vector.app.databinding.FragmentRoomDetailBinding
|
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.AttachmentTypeSelectorView
|
||||||
import im.vector.app.features.attachments.AttachmentsHelper
|
import im.vector.app.features.attachments.AttachmentsHelper
|
||||||
import im.vector.app.features.attachments.ContactAttachment
|
import im.vector.app.features.attachments.ContactAttachment
|
||||||
|
@ -336,6 +338,7 @@ class RoomDetailFragment @Inject constructor(
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
analyticsScreenName = Screen.ScreenName.Room
|
||||||
setFragmentResultListener(MigrateRoomBottomSheet.REQUEST_KEY) { _, bundle ->
|
setFragmentResultListener(MigrateRoomBottomSheet.REQUEST_KEY) { _, bundle ->
|
||||||
bundle.getString(MigrateRoomBottomSheet.BUNDLE_KEY_REPLACEMENT_ROOM)?.let { replacementRoomId ->
|
bundle.getString(MigrateRoomBottomSheet.BUNDLE_KEY_REPLACEMENT_ROOM)?.let { replacementRoomId ->
|
||||||
roomDetailViewModel.handle(RoomDetailAction.RoomUpgradeSuccess(replacementRoomId))
|
roomDetailViewModel.handle(RoomDetailAction.RoomUpgradeSuccess(replacementRoomId))
|
||||||
|
@ -1396,6 +1399,7 @@ class RoomDetailFragment @Inject constructor(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (text.isNotBlank()) {
|
if (text.isNotBlank()) {
|
||||||
|
analyticsTracker.capture(Click(name = Click.Name.SendMessageButton))
|
||||||
// We collapse ASAP, if not there will be a slight annoying delay
|
// We collapse ASAP, if not there will be a slight annoying delay
|
||||||
views.composerLayout.collapse(true)
|
views.composerLayout.collapse(true)
|
||||||
lockSendButton = 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.platform.VectorViewModel
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.core.utils.BehaviorDataSource
|
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.DecryptionFailureTracker
|
||||||
|
import im.vector.app.features.analytics.extensions.toAnalyticsJoinedRoom
|
||||||
import im.vector.app.features.call.conference.ConferenceEvent
|
import im.vector.app.features.call.conference.ConferenceEvent
|
||||||
import im.vector.app.features.call.conference.JitsiActiveConferenceHolder
|
import im.vector.app.features.call.conference.JitsiActiveConferenceHolder
|
||||||
import im.vector.app.features.call.conference.JitsiService
|
import im.vector.app.features.call.conference.JitsiService
|
||||||
|
@ -114,6 +116,7 @@ class RoomDetailViewModel @AssistedInject constructor(
|
||||||
private val chatEffectManager: ChatEffectManager,
|
private val chatEffectManager: ChatEffectManager,
|
||||||
private val directRoomHelper: DirectRoomHelper,
|
private val directRoomHelper: DirectRoomHelper,
|
||||||
private val jitsiService: JitsiService,
|
private val jitsiService: JitsiService,
|
||||||
|
private val analyticsTracker: AnalyticsTracker,
|
||||||
private val activeConferenceHolder: JitsiActiveConferenceHolder,
|
private val activeConferenceHolder: JitsiActiveConferenceHolder,
|
||||||
private val decryptionFailureTracker: DecryptionFailureTracker,
|
private val decryptionFailureTracker: DecryptionFailureTracker,
|
||||||
timelineFactory: TimelineFactory,
|
timelineFactory: TimelineFactory,
|
||||||
|
@ -730,7 +733,10 @@ class RoomDetailViewModel @AssistedInject constructor(
|
||||||
|
|
||||||
private fun handleAcceptInvite() {
|
private fun handleAcceptInvite() {
|
||||||
viewModelScope.launch {
|
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.extensions.exhaustive
|
||||||
import im.vector.app.core.platform.VectorViewModel
|
import im.vector.app.core.platform.VectorViewModel
|
||||||
import im.vector.app.core.resources.StringProvider
|
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.attachments.toContentAttachmentData
|
||||||
import im.vector.app.features.command.CommandParser
|
import im.vector.app.features.command.CommandParser
|
||||||
import im.vector.app.features.command.ParsedCommand
|
import im.vector.app.features.command.ParsedCommand
|
||||||
|
@ -69,6 +71,7 @@ class MessageComposerViewModel @AssistedInject constructor(
|
||||||
private val commandParser: CommandParser,
|
private val commandParser: CommandParser,
|
||||||
private val rainbowGenerator: RainbowGenerator,
|
private val rainbowGenerator: RainbowGenerator,
|
||||||
private val voiceMessageHelper: VoiceMessageHelper,
|
private val voiceMessageHelper: VoiceMessageHelper,
|
||||||
|
private val analyticsTracker: AnalyticsTracker,
|
||||||
private val voicePlayerHelper: VoicePlayerHelper
|
private val voicePlayerHelper: VoicePlayerHelper
|
||||||
) : VectorViewModel<MessageComposerViewState, MessageComposerAction, MessageComposerViewEvents>(initialState) {
|
) : VectorViewModel<MessageComposerViewState, MessageComposerAction, MessageComposerViewEvents>(initialState) {
|
||||||
|
|
||||||
|
@ -521,6 +524,7 @@ class MessageComposerViewModel @AssistedInject constructor(
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
session.getRoomSummary(command.roomAlias)
|
session.getRoomSummary(command.roomAlias)
|
||||||
|
?.also { analyticsTracker.capture(it.toAnalyticsJoinedRoom()) }
|
||||||
?.roomId
|
?.roomId
|
||||||
?.let {
|
?.let {
|
||||||
_viewEvents.post(MessageComposerViewEvents.JoinRoomCommandSuccess(it))
|
_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.extensions.replaceFragment
|
||||||
import im.vector.app.core.platform.VectorBaseActivity
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
import im.vector.app.databinding.ActivityFilteredRoomsBinding
|
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.RoomListDisplayMode
|
||||||
import im.vector.app.features.home.room.list.RoomListFragment
|
import im.vector.app.features.home.room.list.RoomListFragment
|
||||||
import im.vector.app.features.home.room.list.RoomListParams
|
import im.vector.app.features.home.room.list.RoomListParams
|
||||||
|
@ -42,6 +43,7 @@ class FilteredRoomsActivity : VectorBaseActivity<ActivityFilteredRoomsBinding>()
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
analyticsScreenName = Screen.ScreenName.RoomFilter
|
||||||
configureToolbar(views.filteredRoomsToolbar)
|
configureToolbar(views.filteredRoomsToolbar)
|
||||||
if (isFirstCreation()) {
|
if (isFirstCreation()) {
|
||||||
val params = RoomListParams(RoomListDisplayMode.FILTERED)
|
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.platform.VectorBaseFragment
|
||||||
import im.vector.app.core.resources.UserPreferencesProvider
|
import im.vector.app.core.resources.UserPreferencesProvider
|
||||||
import im.vector.app.databinding.FragmentRoomListBinding
|
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.RoomListDisplayMode
|
||||||
import im.vector.app.features.home.room.filtered.FilteredRoomFooterItem
|
import im.vector.app.features.home.room.filtered.FilteredRoomFooterItem
|
||||||
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet
|
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet
|
||||||
|
@ -100,6 +101,15 @@ class RoomListFragment @Inject constructor(
|
||||||
private val adapterInfosList = mutableListOf<SectionAdapterInfo>()
|
private val adapterInfosList = mutableListOf<SectionAdapterInfo>()
|
||||||
private var concatAdapter: ConcatAdapter? = null
|
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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
views.stateView.contentView = views.roomListView
|
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.extensions.exhaustive
|
||||||
import im.vector.app.core.platform.VectorViewModel
|
import im.vector.app.core.platform.VectorViewModel
|
||||||
import im.vector.app.core.resources.StringProvider
|
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.displayname.getBestName
|
||||||
import im.vector.app.features.invite.AutoAcceptInvites
|
import im.vector.app.features.invite.AutoAcceptInvites
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
|
@ -56,7 +58,8 @@ class RoomListViewModel @AssistedInject constructor(
|
||||||
stringProvider: StringProvider,
|
stringProvider: StringProvider,
|
||||||
appStateHandler: AppStateHandler,
|
appStateHandler: AppStateHandler,
|
||||||
vectorPreferences: VectorPreferences,
|
vectorPreferences: VectorPreferences,
|
||||||
autoAcceptInvites: AutoAcceptInvites
|
autoAcceptInvites: AutoAcceptInvites,
|
||||||
|
private val analyticsTracker: AnalyticsTracker
|
||||||
) : VectorViewModel<RoomListViewState, RoomListAction, RoomListViewEvents>(initialState) {
|
) : VectorViewModel<RoomListViewState, RoomListAction, RoomListViewEvents>(initialState) {
|
||||||
|
|
||||||
@AssistedFactory
|
@AssistedFactory
|
||||||
|
@ -223,6 +226,7 @@ class RoomListViewModel @AssistedInject constructor(
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
try {
|
try {
|
||||||
room.join()
|
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.
|
// 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
|
// Instead, we wait for the room to be joined
|
||||||
} catch (failure: Throwable) {
|
} 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.ToolbarConfigurable
|
||||||
import im.vector.app.core.platform.VectorBaseActivity
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
import im.vector.app.databinding.ActivityLoginBinding
|
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.home.HomeActivity
|
||||||
import im.vector.app.features.login.terms.LoginTermsFragment
|
import im.vector.app.features.login.terms.LoginTermsFragment
|
||||||
import im.vector.app.features.login.terms.LoginTermsFragmentArgument
|
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 getCoordinatorLayout() = views.coordinatorLayout
|
||||||
|
|
||||||
override fun initUiAndData() {
|
override fun initUiAndData() {
|
||||||
|
analyticsScreenName = Screen.ScreenName.Login
|
||||||
|
|
||||||
if (isFirstCreation()) {
|
if (isFirstCreation()) {
|
||||||
addFirstFragment()
|
addFirstFragment()
|
||||||
}
|
}
|
||||||
|
@ -200,6 +203,10 @@ open class LoginActivity : VectorBaseActivity<ActivityLoginBinding>(), ToolbarCo
|
||||||
|
|
||||||
private fun updateWithState(loginViewState: LoginViewState) {
|
private fun updateWithState(loginViewState: LoginViewState) {
|
||||||
if (loginViewState.isUserLogged()) {
|
if (loginViewState.isUserLogged()) {
|
||||||
|
if (loginViewState.signMode == SignMode.SignUp) {
|
||||||
|
// change the screen name
|
||||||
|
analyticsScreenName = Screen.ScreenName.Register
|
||||||
|
}
|
||||||
val intent = HomeActivity.newIntent(
|
val intent = HomeActivity.newIntent(
|
||||||
this,
|
this,
|
||||||
accountCreation = loginViewState.signMode == SignMode.SignUp
|
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.isEmail
|
||||||
import im.vector.app.core.extensions.toReducedUrl
|
import im.vector.app.core.extensions.toReducedUrl
|
||||||
import im.vector.app.databinding.FragmentLoginResetPasswordBinding
|
import im.vector.app.databinding.FragmentLoginResetPasswordBinding
|
||||||
|
import im.vector.app.features.analytics.plan.Screen
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
@ -46,6 +47,11 @@ class LoginResetPasswordFragment @Inject constructor() : AbstractLoginFragment<F
|
||||||
// Show warning only once
|
// Show warning only once
|
||||||
private var showWarning = true
|
private var showWarning = true
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
analyticsScreenName = Screen.ScreenName.ForgotPassword
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
}
|
||||||
|
|
||||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginResetPasswordBinding {
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginResetPasswordBinding {
|
||||||
return FragmentLoginResetPasswordBinding.inflate(inflater, container, false)
|
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.BuildConfig
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.databinding.FragmentLoginSplashBinding
|
import im.vector.app.databinding.FragmentLoginSplashBinding
|
||||||
|
import im.vector.app.features.analytics.plan.Screen
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
import org.matrix.android.sdk.api.failure.Failure
|
import org.matrix.android.sdk.api.failure.Failure
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
|
@ -42,6 +43,11 @@ class LoginSplashFragment @Inject constructor(
|
||||||
return FragmentLoginSplashBinding.inflate(inflater, container, false)
|
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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,8 @@ import androidx.core.app.RemoteInput
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
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 im.vector.app.features.session.coroutineScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
|
@ -41,6 +43,7 @@ class NotificationBroadcastReceiver : BroadcastReceiver() {
|
||||||
|
|
||||||
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager
|
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager
|
||||||
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
|
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
|
||||||
|
@Inject lateinit var analyticsTracker: AnalyticsTracker
|
||||||
|
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
if (intent == null || context == null) return
|
if (intent == null || context == null) return
|
||||||
|
@ -79,7 +82,10 @@ class NotificationBroadcastReceiver : BroadcastReceiver() {
|
||||||
val room = session.getRoom(roomId)
|
val room = session.getRoom(roomId)
|
||||||
if (room != null) {
|
if (room != null) {
|
||||||
session.coroutineScope.launch {
|
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) {
|
override fun onPublicRoomJoin(publicRoom: PublicRoom) {
|
||||||
Timber.v("PublicRoomJoinClicked: $publicRoom")
|
Timber.v("PublicRoomJoinClicked: $publicRoom")
|
||||||
viewModel.handle(RoomDirectoryAction.JoinRoom(publicRoom.roomId))
|
viewModel.handle(RoomDirectoryAction.JoinRoom(publicRoom))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadMore() {
|
override fun loadMore() {
|
||||||
|
|
|
@ -17,10 +17,11 @@
|
||||||
package im.vector.app.features.roomdirectory
|
package im.vector.app.features.roomdirectory
|
||||||
|
|
||||||
import im.vector.app.core.platform.VectorViewModelAction
|
import im.vector.app.core.platform.VectorViewModelAction
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
|
||||||
|
|
||||||
sealed class RoomDirectoryAction : VectorViewModelAction {
|
sealed class RoomDirectoryAction : VectorViewModelAction {
|
||||||
data class SetRoomDirectoryData(val roomDirectoryData: RoomDirectoryData) : RoomDirectoryAction()
|
data class SetRoomDirectoryData(val roomDirectoryData: RoomDirectoryData) : RoomDirectoryAction()
|
||||||
data class FilterWith(val filter: String) : RoomDirectoryAction()
|
data class FilterWith(val filter: String) : RoomDirectoryAction()
|
||||||
object LoadMore : 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.extensions.popBackstack
|
||||||
import im.vector.app.core.platform.VectorBaseActivity
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
import im.vector.app.databinding.ActivitySimpleBinding
|
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.matrixto.MatrixToBottomSheet
|
||||||
import im.vector.app.features.navigation.Navigator
|
import im.vector.app.features.navigation.Navigator
|
||||||
import im.vector.app.features.roomdirectory.createroom.CreateRoomArgs
|
import im.vector.app.features.roomdirectory.createroom.CreateRoomArgs
|
||||||
|
@ -50,6 +51,7 @@ class RoomDirectoryActivity : VectorBaseActivity<ActivitySimpleBinding>(), Matri
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
analyticsScreenName = Screen.ScreenName.RoomDirectory
|
||||||
sharedActionViewModel = viewModelProvider.get(RoomDirectorySharedActionViewModel::class.java)
|
sharedActionViewModel = viewModelProvider.get(RoomDirectorySharedActionViewModel::class.java)
|
||||||
|
|
||||||
if (isFirstCreation()) {
|
if (isFirstCreation()) {
|
||||||
|
|
|
@ -27,6 +27,8 @@ import dagger.assisted.AssistedInject
|
||||||
import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
||||||
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||||
import im.vector.app.core.platform.VectorViewModel
|
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 im.vector.app.features.settings.VectorPreferences
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
@ -45,6 +47,7 @@ class RoomDirectoryViewModel @AssistedInject constructor(
|
||||||
@Assisted initialState: PublicRoomsViewState,
|
@Assisted initialState: PublicRoomsViewState,
|
||||||
vectorPreferences: VectorPreferences,
|
vectorPreferences: VectorPreferences,
|
||||||
private val session: Session,
|
private val session: Session,
|
||||||
|
private val analyticsTracker: AnalyticsTracker,
|
||||||
private val explicitTermFilter: ExplicitTermFilter
|
private val explicitTermFilter: ExplicitTermFilter
|
||||||
) : VectorViewModel<PublicRoomsViewState, RoomDirectoryAction, RoomDirectoryViewEvents>(initialState) {
|
) : VectorViewModel<PublicRoomsViewState, RoomDirectoryAction, RoomDirectoryViewEvents>(initialState) {
|
||||||
|
|
||||||
|
@ -213,7 +216,7 @@ class RoomDirectoryViewModel @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun joinRoom(action: RoomDirectoryAction.JoinRoom) = withState { state ->
|
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()) {
|
if (roomMembershipChange?.isInProgress().orFalse()) {
|
||||||
// Request already sent, should not happen
|
// Request already sent, should not happen
|
||||||
Timber.w("Try to join an already joining room. 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)
|
val viaServers = listOfNotNull(state.roomDirectoryData.homeServer)
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
try {
|
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.
|
// 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
|
// Instead, we wait for the room to be joined
|
||||||
} catch (failure: Throwable) {
|
} 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.ToolbarConfigurable
|
||||||
import im.vector.app.core.platform.VectorBaseActivity
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
import im.vector.app.databinding.ActivitySimpleBinding
|
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.RoomDirectorySharedAction
|
||||||
import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel
|
import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
@ -62,6 +63,7 @@ class CreateRoomActivity : VectorBaseActivity<ActivitySimpleBinding>(), ToolbarC
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
analyticsScreenName = Screen.ScreenName.CreateRoom
|
||||||
sharedActionViewModel = viewModelProvider.get(RoomDirectorySharedActionViewModel::class.java)
|
sharedActionViewModel = viewModelProvider.get(RoomDirectorySharedActionViewModel::class.java)
|
||||||
sharedActionViewModel
|
sharedActionViewModel
|
||||||
.stream()
|
.stream()
|
||||||
|
|
|
@ -30,6 +30,8 @@ import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
||||||
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||||
import im.vector.app.core.extensions.exhaustive
|
import im.vector.app.core.extensions.exhaustive
|
||||||
import im.vector.app.core.platform.VectorViewModel
|
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.getElementWellknown
|
||||||
import im.vector.app.features.raw.wellknown.isE2EByDefault
|
import im.vector.app.features.raw.wellknown.isE2EByDefault
|
||||||
import kotlinx.coroutines.Dispatchers
|
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 org.matrix.android.sdk.api.session.room.model.create.RestrictedRoomPreset
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
class CreateRoomViewModel @AssistedInject constructor(@Assisted private val initialState: CreateRoomViewState,
|
class CreateRoomViewModel @AssistedInject constructor(
|
||||||
private val session: Session,
|
@Assisted private val initialState: CreateRoomViewState,
|
||||||
private val rawService: RawService,
|
private val session: Session,
|
||||||
appStateHandler: AppStateHandler
|
private val rawService: RawService,
|
||||||
|
appStateHandler: AppStateHandler,
|
||||||
|
private val analyticsTracker: AnalyticsTracker
|
||||||
) : VectorViewModel<CreateRoomViewState, CreateRoomAction, CreateRoomViewEvents>(initialState) {
|
) : VectorViewModel<CreateRoomViewState, CreateRoomAction, CreateRoomViewEvents>(initialState) {
|
||||||
|
|
||||||
@AssistedFactory
|
@AssistedFactory
|
||||||
|
@ -296,7 +300,7 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted private val init
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
runCatching { session.createRoom(createRoomParams) }.fold(
|
runCatching { session.createRoom(createRoomParams) }.fold(
|
||||||
{ roomId ->
|
{ roomId ->
|
||||||
|
analyticsTracker.capture(CreatedRoom(isDM = createRoomParams.isDirect.orFalse()))
|
||||||
if (state.parentSpaceId != null) {
|
if (state.parentSpaceId != null) {
|
||||||
// add it as a child
|
// add it as a child
|
||||||
try {
|
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.OnBackPressed
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.databinding.FragmentRoomDirectoryPickerBinding
|
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.RoomDirectoryAction
|
||||||
import im.vector.app.features.roomdirectory.RoomDirectoryData
|
import im.vector.app.features.roomdirectory.RoomDirectoryData
|
||||||
import im.vector.app.features.roomdirectory.RoomDirectoryServer
|
import im.vector.app.features.roomdirectory.RoomDirectoryServer
|
||||||
|
@ -52,6 +53,11 @@ class RoomDirectoryPickerFragment @Inject constructor(private val roomDirectoryP
|
||||||
return FragmentRoomDirectoryPickerBinding.inflate(inflater, container, false)
|
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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@ data class RoomPreviewData(
|
||||||
val roomAlias: String? = null,
|
val roomAlias: String? = null,
|
||||||
val roomType: String? = null,
|
val roomType: String? = null,
|
||||||
val topic: String? = null,
|
val topic: String? = null,
|
||||||
|
val numJoinedMembers: Int? = null,
|
||||||
val worldReadable: Boolean = false,
|
val worldReadable: Boolean = false,
|
||||||
val avatarUrl: String? = null,
|
val avatarUrl: String? = null,
|
||||||
val homeServers: List<String> = emptyList(),
|
val homeServers: List<String> = emptyList(),
|
||||||
|
@ -69,6 +70,7 @@ class RoomPreviewActivity : VectorBaseActivity<ActivitySimpleBinding>(), Toolbar
|
||||||
roomName = publicRoom.name,
|
roomName = publicRoom.name,
|
||||||
roomAlias = publicRoom.getPrimaryAlias(),
|
roomAlias = publicRoom.getPrimaryAlias(),
|
||||||
topic = publicRoom.topic,
|
topic = publicRoom.topic,
|
||||||
|
numJoinedMembers = publicRoom.numJoinedMembers,
|
||||||
worldReadable = publicRoom.worldReadable,
|
worldReadable = publicRoom.worldReadable,
|
||||||
avatarUrl = publicRoom.avatarUrl,
|
avatarUrl = publicRoom.avatarUrl,
|
||||||
homeServers = listOfNotNull(roomDirectoryData.homeServer)
|
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.extensions.exhaustive
|
||||||
import im.vector.app.core.platform.EmptyViewEvents
|
import im.vector.app.core.platform.EmptyViewEvents
|
||||||
import im.vector.app.core.platform.VectorViewModel
|
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 im.vector.app.features.roomdirectory.JoinState
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.launchIn
|
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 org.matrix.android.sdk.flow.flow
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
class RoomPreviewViewModel @AssistedInject constructor(@Assisted private val initialState: RoomPreviewViewState,
|
class RoomPreviewViewModel @AssistedInject constructor(
|
||||||
private val session: Session) :
|
@Assisted private val initialState: RoomPreviewViewState,
|
||||||
VectorViewModel<RoomPreviewViewState, RoomPreviewAction, EmptyViewEvents>(initialState) {
|
private val analyticsTracker: AnalyticsTracker,
|
||||||
|
private val session: Session
|
||||||
|
) : VectorViewModel<RoomPreviewViewState, RoomPreviewAction, EmptyViewEvents>(initialState) {
|
||||||
|
|
||||||
@AssistedFactory
|
@AssistedFactory
|
||||||
interface Factory : MavericksAssistedViewModelFactory<RoomPreviewViewModel, RoomPreviewViewState> {
|
interface Factory : MavericksAssistedViewModelFactory<RoomPreviewViewModel, RoomPreviewViewState> {
|
||||||
|
@ -243,6 +248,11 @@ class RoomPreviewViewModel @AssistedInject constructor(@Assisted private val ini
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
try {
|
try {
|
||||||
session.joinRoom(state.roomId, viaServers = state.homeServers)
|
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.
|
// 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
|
// Instead, we wait for the room to be joined
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
|
|
|
@ -33,6 +33,7 @@ data class RoomPreviewViewState(
|
||||||
|
|
||||||
val roomName: String? = null,
|
val roomName: String? = null,
|
||||||
val roomTopic: String? = null,
|
val roomTopic: String? = null,
|
||||||
|
val numJoinMembers: Int? = null,
|
||||||
val avatarUrl: String? = null,
|
val avatarUrl: String? = null,
|
||||||
|
|
||||||
val shouldPeekFromServer: Boolean = false,
|
val shouldPeekFromServer: Boolean = false,
|
||||||
|
@ -56,6 +57,7 @@ data class RoomPreviewViewState(
|
||||||
homeServers = args.homeServers,
|
homeServers = args.homeServers,
|
||||||
roomName = args.roomName,
|
roomName = args.roomName,
|
||||||
roomTopic = args.topic,
|
roomTopic = args.topic,
|
||||||
|
numJoinMembers = args.numJoinedMembers,
|
||||||
avatarUrl = args.avatarUrl,
|
avatarUrl = args.avatarUrl,
|
||||||
shouldPeekFromServer = args.peekFromServer,
|
shouldPeekFromServer = args.peekFromServer,
|
||||||
fromEmailInvite = args.fromEmailInvite,
|
fromEmailInvite = args.fromEmailInvite,
|
||||||
|
@ -64,6 +66,6 @@ data class RoomPreviewViewState(
|
||||||
|
|
||||||
fun matrixItem(): MatrixItem {
|
fun matrixItem(): MatrixItem {
|
||||||
return if (roomType == RoomType.SPACE) MatrixItem.SpaceItem(roomId, roomName ?: roomAlias, avatarUrl)
|
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.DialogShareQrCodeBinding
|
||||||
import im.vector.app.databinding.FragmentMatrixProfileBinding
|
import im.vector.app.databinding.FragmentMatrixProfileBinding
|
||||||
import im.vector.app.databinding.ViewStubRoomMemberProfileHeaderBinding
|
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.crypto.verification.VerificationBottomSheet
|
||||||
import im.vector.app.features.displayname.getBestName
|
import im.vector.app.features.displayname.getBestName
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
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 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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
setupToolbar(views.matrixProfileToolbar)
|
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.core.utils.startSharePlainTextIntent
|
||||||
import im.vector.app.databinding.FragmentMatrixProfileBinding
|
import im.vector.app.databinding.FragmentMatrixProfileBinding
|
||||||
import im.vector.app.databinding.ViewStubRoomProfileHeaderBinding
|
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.AvatarRenderer
|
||||||
import im.vector.app.features.home.room.detail.RoomDetailPendingAction
|
import im.vector.app.features.home.room.detail.RoomDetailPendingAction
|
||||||
import im.vector.app.features.home.room.detail.RoomDetailPendingActionStore
|
import im.vector.app.features.home.room.detail.RoomDetailPendingActionStore
|
||||||
|
@ -88,6 +89,7 @@ class RoomProfileFragment @Inject constructor(
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
analyticsScreenName = Screen.ScreenName.RoomSettings
|
||||||
setFragmentResultListener(MigrateRoomBottomSheet.REQUEST_KEY) { _, bundle ->
|
setFragmentResultListener(MigrateRoomBottomSheet.REQUEST_KEY) { _, bundle ->
|
||||||
bundle.getString(MigrateRoomBottomSheet.BUNDLE_KEY_REPLACEMENT_ROOM)?.let { replacementRoomId ->
|
bundle.getString(MigrateRoomBottomSheet.BUNDLE_KEY_REPLACEMENT_ROOM)?.let { replacementRoomId ->
|
||||||
roomDetailPendingActionStore.data = RoomDetailPendingAction.OpenRoom(replacementRoomId, closeCurrentRoom = true)
|
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.saveMedia
|
||||||
import im.vector.app.core.utils.shareMedia
|
import im.vector.app.core.utils.shareMedia
|
||||||
import im.vector.app.databinding.FragmentRoomUploadsBinding
|
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.home.AvatarRenderer
|
||||||
import im.vector.app.features.notifications.NotificationUtils
|
import im.vector.app.features.notifications.NotificationUtils
|
||||||
import im.vector.app.features.roomprofile.RoomProfileArgs
|
import im.vector.app.features.roomprofile.RoomProfileArgs
|
||||||
|
@ -54,6 +55,11 @@ class RoomUploadsFragment @Inject constructor(
|
||||||
return FragmentRoomUploadsBinding.inflate(inflater, container, false)
|
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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
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.extensions.singletonEntryPoint
|
||||||
import im.vector.app.core.platform.VectorBaseActivity
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
import im.vector.app.core.utils.toast
|
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.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
@ -37,6 +39,18 @@ import reactivecircus.flowbinding.android.view.clicks
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
abstract class VectorSettingsBaseFragment : PreferenceFragmentCompat(), MavericksView {
|
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 {
|
val vectorActivity: VectorBaseActivity<*> by lazy {
|
||||||
activity as VectorBaseActivity<*>
|
activity as VectorBaseActivity<*>
|
||||||
|
@ -47,7 +61,6 @@ abstract class VectorSettingsBaseFragment : PreferenceFragmentCompat(), Maverick
|
||||||
// members
|
// members
|
||||||
protected lateinit var session: Session
|
protected lateinit var session: Session
|
||||||
protected lateinit var errorFormatter: ErrorFormatter
|
protected lateinit var errorFormatter: ErrorFormatter
|
||||||
protected lateinit var analytics: VectorAnalytics
|
|
||||||
|
|
||||||
/* ==========================================================================================
|
/* ==========================================================================================
|
||||||
* Views
|
* Views
|
||||||
|
@ -72,17 +85,23 @@ abstract class VectorSettingsBaseFragment : PreferenceFragmentCompat(), Maverick
|
||||||
super.onAttach(context)
|
super.onAttach(context)
|
||||||
session = singletonEntryPoint.activeSessionHolder().getActiveSession()
|
session = singletonEntryPoint.activeSessionHolder().getActiveSession()
|
||||||
errorFormatter = singletonEntryPoint.errorFormatter()
|
errorFormatter = singletonEntryPoint.errorFormatter()
|
||||||
analytics = singletonEntryPoint.analytics()
|
analyticsTracker = singletonEntryPoint.analyticsTracker()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
Timber.i("onResume Fragment ${javaClass.simpleName}")
|
Timber.i("onResume Fragment ${javaClass.simpleName}")
|
||||||
|
screenEvent = analyticsScreenName?.let { ScreenEvent(it) }
|
||||||
vectorActivity.supportActionBar?.setTitle(titleRes)
|
vectorActivity.supportActionBar?.setTitle(titleRes)
|
||||||
// find the view from parent activity
|
// find the view from parent activity
|
||||||
mLoadingView = vectorActivity.findViewById(R.id.vector_settings_spinner_views)
|
mLoadingView = vectorActivity.findViewById(R.id.vector_settings_spinner_views)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
screenEvent?.send(analyticsTracker)
|
||||||
|
}
|
||||||
|
|
||||||
abstract fun bindPref()
|
abstract fun bindPref()
|
||||||
|
|
||||||
abstract var titleRes: Int
|
abstract var titleRes: Int
|
||||||
|
|
|
@ -16,8 +16,10 @@
|
||||||
|
|
||||||
package im.vector.app.features.settings
|
package im.vector.app.features.settings
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.preference.VectorPreference
|
import im.vector.app.core.preference.VectorPreference
|
||||||
|
import im.vector.app.features.analytics.plan.Screen
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class VectorSettingsRootFragment @Inject constructor() : VectorSettingsBaseFragment() {
|
class VectorSettingsRootFragment @Inject constructor() : VectorSettingsBaseFragment() {
|
||||||
|
@ -25,6 +27,11 @@ class VectorSettingsRootFragment @Inject constructor() : VectorSettingsBaseFragm
|
||||||
override var titleRes: Int = R.string.title_activity_settings
|
override var titleRes: Int = R.string.title_activity_settings
|
||||||
override val preferenceXmlRes = R.xml.vector_settings_root
|
override val preferenceXmlRes = R.xml.vector_settings_root
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
analyticsScreenName = Screen.ScreenName.Settings
|
||||||
|
}
|
||||||
|
|
||||||
override fun bindPref() {
|
override fun bindPref() {
|
||||||
tintIcons()
|
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.openFileSelection
|
||||||
import im.vector.app.core.utils.toast
|
import im.vector.app.core.utils.toast
|
||||||
import im.vector.app.databinding.DialogImportE2eKeysBinding
|
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.AnalyticsConsentViewActions
|
||||||
import im.vector.app.features.analytics.ui.consent.AnalyticsConsentViewModel
|
import im.vector.app.features.analytics.ui.consent.AnalyticsConsentViewModel
|
||||||
import im.vector.app.features.analytics.ui.consent.AnalyticsConsentViewState
|
import im.vector.app.features.analytics.ui.consent.AnalyticsConsentViewState
|
||||||
|
@ -91,6 +92,11 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
|
||||||
|
|
||||||
private val analyticsConsentViewModel: AnalyticsConsentViewModel by fragmentViewModel()
|
private val analyticsConsentViewModel: AnalyticsConsentViewModel by fragmentViewModel()
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
analyticsScreenName = Screen.ScreenName.SettingsSecurity
|
||||||
|
}
|
||||||
|
|
||||||
// cryptography
|
// cryptography
|
||||||
private val mCryptographyCategory by lazy {
|
private val mCryptographyCategory by lazy {
|
||||||
findPreference<PreferenceCategory>(VectorPreferences.SETTINGS_CRYPTOGRAPHY_PREFERENCE_KEY)!!
|
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.databinding.FragmentDeactivateAccountBinding
|
||||||
import im.vector.app.features.MainActivity
|
import im.vector.app.features.MainActivity
|
||||||
import im.vector.app.features.MainActivityArgs
|
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.auth.ReAuthActivity
|
||||||
import im.vector.app.features.settings.VectorSettingsActivity
|
import im.vector.app.features.settings.VectorSettingsActivity
|
||||||
import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
|
import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
|
||||||
|
@ -47,7 +48,7 @@ class DeactivateAccountFragment @Inject constructor() : VectorBaseFragment<Fragm
|
||||||
private val reAuthActivityResultLauncher = registerStartForActivityResult { activityResult ->
|
private val reAuthActivityResultLauncher = registerStartForActivityResult { activityResult ->
|
||||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||||
when (activityResult.data?.extras?.getString(ReAuthActivity.RESULT_FLOW_TYPE)) {
|
when (activityResult.data?.extras?.getString(ReAuthActivity.RESULT_FLOW_TYPE)) {
|
||||||
LoginFlowTypes.SSO -> {
|
LoginFlowTypes.SSO -> {
|
||||||
viewModel.handle(DeactivateAccountAction.SsoAuthDone)
|
viewModel.handle(DeactivateAccountAction.SsoAuthDone)
|
||||||
}
|
}
|
||||||
LoginFlowTypes.PASSWORD -> {
|
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() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
(activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.deactivate_account_title)
|
(activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.deactivate_account_title)
|
||||||
|
|
|
@ -16,8 +16,10 @@
|
||||||
|
|
||||||
package im.vector.app.features.settings.notifications
|
package im.vector.app.features.settings.notifications
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.preference.VectorPreferenceCategory
|
import im.vector.app.core.preference.VectorPreferenceCategory
|
||||||
|
import im.vector.app.features.analytics.plan.Screen
|
||||||
import org.matrix.android.sdk.api.pushrules.RuleIds
|
import org.matrix.android.sdk.api.pushrules.RuleIds
|
||||||
|
|
||||||
class VectorSettingsDefaultNotificationPreferenceFragment :
|
class VectorSettingsDefaultNotificationPreferenceFragment :
|
||||||
|
@ -34,6 +36,11 @@ class VectorSettingsDefaultNotificationPreferenceFragment :
|
||||||
"SETTINGS_PUSH_RULE_MESSAGES_IN_E2E_GROUP_CHAT_PREFERENCE_KEY" to RuleIds.RULE_ID_ENCRYPTED
|
"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() {
|
override fun bindPref() {
|
||||||
super.bindPref()
|
super.bindPref()
|
||||||
val category = findPreference<VectorPreferenceCategory>("SETTINGS_DEFAULT")!!
|
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.VectorCheckboxPreference
|
||||||
import im.vector.app.core.preference.VectorPreference
|
import im.vector.app.core.preference.VectorPreference
|
||||||
import im.vector.app.core.preference.VectorPreferenceCategory
|
import im.vector.app.core.preference.VectorPreferenceCategory
|
||||||
|
import im.vector.app.features.analytics.plan.Screen
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
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
|
import org.matrix.android.sdk.api.pushrules.toJson
|
||||||
|
|
||||||
class VectorSettingsKeywordAndMentionsNotificationPreferenceFragment :
|
class VectorSettingsKeywordAndMentionsNotificationPreferenceFragment :
|
||||||
VectorSettingsPushRuleNotificationPreferenceFragment() {
|
VectorSettingsPushRuleNotificationPreferenceFragment() {
|
||||||
|
|
||||||
override var titleRes: Int = R.string.settings_notification_mentions_and_keywords
|
override var titleRes: Int = R.string.settings_notification_mentions_and_keywords
|
||||||
|
|
||||||
|
@ -42,6 +43,11 @@ class VectorSettingsKeywordAndMentionsNotificationPreferenceFragment :
|
||||||
|
|
||||||
private var keywordsHasFocus = false
|
private var keywordsHasFocus = false
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
analyticsScreenName = Screen.ScreenName.SettingsMentionsAndKeywords
|
||||||
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
session.getKeywords().observe(viewLifecycleOwner, this::updateWithKeywords)
|
session.getKeywords().observe(viewLifecycleOwner, this::updateWithKeywords)
|
||||||
|
@ -71,7 +77,7 @@ class VectorSettingsKeywordAndMentionsNotificationPreferenceFragment :
|
||||||
val keywords = editKeywordPreference.keywords
|
val keywords = editKeywordPreference.keywords
|
||||||
val newChecked = newValue as Boolean
|
val newChecked = newValue as Boolean
|
||||||
displayLoadingView()
|
displayLoadingView()
|
||||||
updateKeywordPushRules(keywords, newChecked) { result ->
|
updateKeywordPushRules(keywords, newChecked) { result ->
|
||||||
hideLoadingView()
|
hideLoadingView()
|
||||||
if (!isAdded) {
|
if (!isAdded) {
|
||||||
return@updateKeywordPushRules
|
return@updateKeywordPushRules
|
||||||
|
@ -88,7 +94,7 @@ class VectorSettingsKeywordAndMentionsNotificationPreferenceFragment :
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
editKeywordPreference.listener = object : KeywordPreference.Listener {
|
editKeywordPreference.listener = object : KeywordPreference.Listener {
|
||||||
override fun onFocusDidChange(hasFocus: Boolean) {
|
override fun onFocusDidChange(hasFocus: Boolean) {
|
||||||
keywordsHasFocus = true
|
keywordsHasFocus = true
|
||||||
}
|
}
|
||||||
|
@ -174,8 +180,8 @@ class VectorSettingsKeywordAndMentionsNotificationPreferenceFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
override val prefKeyToPushRuleId = mapOf(
|
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_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_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_MESSAGES_CONTAINING_AT_ROOM_PREFERENCE_KEY" to RuleIds.RULE_ID_ROOM_NOTIF
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue