Add location related analytics (#1241)

* Refactor trackComposer method

* Track location screen

* Refactor isPinDropSharing -> isSharingUserLocation

* Add trackComposer event

* Fix UTs

* Cleanup

* Add AnalyticsLocationType
This commit is contained in:
Alfonso Grillo
2023-07-05 12:54:03 +02:00
committed by GitHub
parent ce14d13962
commit d15d0e0070
12 changed files with 94 additions and 34 deletions
@@ -511,15 +511,21 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
coordinator.actions.sink { [weak self] action in
guard let self else { return }
switch action {
case .selectedLocation(let geoURI):
case .selectedLocation(let geoURI, let isUserLocation):
Task {
_ = await self.roomProxy?.sendLocation(body: geoURI.bodyMessage,
geoURI: geoURI,
description: nil,
zoomLevel: nil,
assetType: .pin)
assetType: isUserLocation ? .sender : .pin)
self.navigationSplitCoordinator.setSheetCoordinator(nil)
}
self.analytics.trackComposer(inThread: false,
isEditing: false,
isReply: false,
locationType: isUserLocation ? .myLocation : .pin,
startsThread: nil)
case .close:
self.navigationSplitCoordinator.setSheetCoordinator(nil)
}
@@ -24,7 +24,7 @@ enum LocationSharingViewError: Error, Hashable {
enum StaticLocationScreenViewModelAction {
case close
case sendLocation(GeoURI)
case sendLocation(GeoURI, isUserLocation: Bool)
}
enum StaticLocationInteractionMode: Hashable {
@@ -33,9 +33,9 @@ enum StaticLocationInteractionMode: Hashable {
}
struct StaticLocationScreenViewState: BindableState {
init(interactionMode: StaticLocationInteractionMode, isPinDropSharing: Bool = true, showsUserLocationMode: ShowUserLocationMode = .hide) {
init(interactionMode: StaticLocationInteractionMode, isSharingUserLocation: Bool = false, showsUserLocationMode: ShowUserLocationMode = .hide) {
self.interactionMode = interactionMode
self.isPinDropSharing = isPinDropSharing
self.isSharingUserLocation = isSharingUserLocation
self.showsUserLocationMode = showsUserLocationMode
switch interactionMode {
@@ -47,10 +47,10 @@ struct StaticLocationScreenViewState: BindableState {
}
let interactionMode: StaticLocationInteractionMode
/// Indicates whether the user has moved around the map to drop a pin somewhere other than their current location
var isPinDropSharing = true
/// Indicates whether the user is sharing his current location
var isSharingUserLocation: Bool
/// Behavior mode of the current user's location, can be hidden, only shown and shown following the user
var showsUserLocationMode: ShowUserLocationMode = .hide
var showsUserLocationMode: ShowUserLocationMode
var bindings = StaticLocationScreenBindings()
@@ -67,10 +67,10 @@ struct StaticLocationScreenViewState: BindableState {
}
}
var showPinInTheCenter: Bool {
var isLocationPickerMode: Bool {
switch interactionMode {
case .picker:
return isPinDropSharing
return true
case .viewOnly:
return false
}
@@ -23,7 +23,7 @@ struct StaticLocationScreenCoordinatorParameters {
enum StaticLocationScreenCoordinatorAction {
case close
case selectedLocation(GeoURI)
case selectedLocation(GeoURI, isUserLocation: Bool)
}
final class StaticLocationScreenCoordinator: CoordinatorProtocol {
@@ -51,8 +51,8 @@ final class StaticLocationScreenCoordinator: CoordinatorProtocol {
switch action {
case .close:
actionsSubject.send(.close)
case .sendLocation(let geoURI):
actionsSubject.send(.selectedLocation(geoURI))
case .sendLocation(let geoURI, let isUserLocation):
actionsSubject.send(.selectedLocation(geoURI, isUserLocation: isUserLocation))
}
}
.store(in: &cancellables)
@@ -36,10 +36,10 @@ class StaticLocationScreenViewModel: StaticLocationScreenViewModelType, StaticLo
actionsSubject.send(.close)
case .selectLocation:
guard let coordinate = state.bindings.mapCenterLocation else { return }
actionsSubject.send(.sendLocation(.init(coordinate: coordinate)))
actionsSubject.send(.sendLocation(.init(coordinate: coordinate), isUserLocation: state.isSharingUserLocation))
case .userDidPan:
state.showsUserLocationMode = .hide
state.isPinDropSharing = true
state.isSharingUserLocation = false
}
}
}
@@ -33,6 +33,7 @@ struct StaticLocationScreen: View {
}
mapView
}
.track(screen: context.viewState.isLocationPickerMode ? .locationSend : .locationView)
.navigationTitle(context.viewState.navigationTitle)
.navigationBarTitleDisplayMode(.inline)
.toolbar { toolbar }
@@ -49,7 +50,7 @@ struct StaticLocationScreen: View {
userDidPan: {
context.send(viewAction: .userDidPan)
})
if context.viewState.showPinInTheCenter {
if context.viewState.isLocationPickerMode {
LocationMarkerView()
}
}
@@ -105,7 +106,7 @@ struct StaticLocationScreen: View {
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: shareMarkerSize, height: shareMarkerSize)
Text(context.viewState.isPinDropSharing ? L10n.screenShareThisLocationAction : L10n.screenShareMyLocationAction)
Text(context.viewState.isSharingUserLocation ? L10n.screenShareMyLocationAction : L10n.screenShareThisLocationAction)
}
}
}
@@ -0,0 +1,33 @@
//
// Copyright 2023 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.
//
import AnalyticsEvents
enum AnalyticsLocationType {
case myLocation
case pin
}
extension AnalyticsEvent.Composer.LocationType {
init(_ analyticsLocationType: AnalyticsLocationType) {
switch analyticsLocationType {
case .myLocation:
self = .MyLocation
case .pin:
self = .PinDrop
}
}
}
@@ -59,6 +59,8 @@ enum AnalyticsScreen: Int {
case spaceBottomSheet
case invites
case createSpace
case locationSend
case locationView
/// The screen name reported to the AnalyticsEvent.
var screenName: AnalyticsEvent.MobileScreen.ScreenName {
@@ -145,6 +147,10 @@ enum AnalyticsScreen: Int {
return .Invites
case .createSpace:
return .CreateSpace
case .locationSend:
return .LocationSend
case .locationView:
return .LocationView
}
}
}
@@ -141,9 +141,19 @@ extension AnalyticsService {
/// - inThread: whether the composer is used in a Thread
/// - isEditing: whether the composer is used to edit a message
/// - isReply: whether the composer is used to reply a message
/// - locationType: the type of the shared location
/// - startsThread: whether the composer is used to start a new thread
func trackComposer(inThread: Bool, isEditing: Bool, isReply: Bool, startsThread: Bool?) {
capture(event: AnalyticsEvent.Composer(inThread: inThread, isEditing: isEditing, isReply: isReply, startsThread: startsThread))
func trackComposer(inThread: Bool,
isEditing: Bool,
isReply: Bool,
locationType: AnalyticsLocationType? = nil,
startsThread: Bool?) {
capture(event: AnalyticsEvent.Composer(inThread: inThread,
isEditing: isEditing,
isLocation: locationType != nil,
isReply: isReply,
locationType: locationType.map { .init($0) },
startsThread: startsThread))
}
/// Track the presentation of a room