Skip to content

Commit

Permalink
Metrics Collection with Segment (#346)
Browse files Browse the repository at this point in the history
* Track events with Segment

* Renamed Exited events to Deactivated

* Include target application in event properties

* Add metrics collection doc

* Fix rebase
  • Loading branch information
dexterleng authored Mar 18, 2021
1 parent c95bc13 commit ff21f9c
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 1 deletion.
1 change: 1 addition & 0 deletions Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ target 'Vimac' do
pod 'MASShortcut'
pod 'Sparkle'
pod 'Preferences'
pod 'Analytics', '~> 4.1'

target 'VimacTests' do
inherit! :search_paths
Expand Down
6 changes: 5 additions & 1 deletion Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
PODS:
- Analytics (4.1.3)
- AXSwift (0.3.1)
- MASShortcut (2.4.0)
- Preferences (2.2.0)
Expand All @@ -11,6 +12,7 @@ PODS:
- Sparkle (1.24.0)

DEPENDENCIES:
- Analytics (~> 4.1)
- AXSwift (~> 0.2)
- MASShortcut
- Preferences
Expand All @@ -20,6 +22,7 @@ DEPENDENCIES:

SPEC REPOS:
trunk:
- Analytics
- AXSwift
- MASShortcut
- Preferences
Expand All @@ -29,6 +32,7 @@ SPEC REPOS:
- Sparkle

SPEC CHECKSUMS:
Analytics: 4c01e3e19d4be86705bad6581a1c2aa5a15a9d22
AXSwift: 24508e48dd103399d5e495201a8157a663029b92
MASShortcut: d9e4909e878661cc42877cc9d6efbe638273ab57
Preferences: 4894cc28df3557336b0b72440c893d95203d3e33
Expand All @@ -37,6 +41,6 @@ SPEC CHECKSUMS:
RxSwift: 81470a2074fa8780320ea5fe4102807cb7118178
Sparkle: 270cd27377bf04e9c128af06e3a22d0f572d6ee3

PODFILE CHECKSUM: 7b6ba65266337439d7050314252aa63d075aba9b
PODFILE CHECKSUM: 1003c25f02e99aebf398427f76ff5303b706e8e5

COCOAPODS: 1.9.2
6 changes: 6 additions & 0 deletions ViMac-Swift/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import MASShortcut
import Sparkle
import LaunchAtLogin
import Preferences
import Segment

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
Expand Down Expand Up @@ -59,6 +60,11 @@ import Preferences
return
}

let configuration = AnalyticsConfiguration(writeKey: "cjSicRrQ0dUgFkhmjDDur7974VfQKTlX")
configuration.trackApplicationLifecycleEvents = true // Enable this to record certain application events automatically!
configuration.recordScreenViews = true // Enable this to record screen views automatically!
Analytics.setup(with: configuration)

setupPreferences()
setupStatusItem()

Expand Down
9 changes: 9 additions & 0 deletions ViMac-Swift/ModeCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Carbon
import Cocoa
import AXSwift
import RxSwift
import Segment

protocol Coordinator {
var windowController: OverlayWindowController { get set }
Expand Down Expand Up @@ -91,6 +92,10 @@ class ModeCoordinator : Coordinator {
return
}

Analytics.shared().track("Scroll Mode Activated", properties: [
"Target Application": frontmostApp.bundleIdentifier as Any
])

let focusedWindowFrame = GeometryUtils.convertAXFrameToGlobal(focusedWindow.frame)
let screenFrame = activeScreenFrame(focusedWindowFrame: focusedWindowFrame)

Expand Down Expand Up @@ -126,6 +131,10 @@ class ModeCoordinator : Coordinator {
}
}

Analytics.shared().track("Hint Mode Activated", properties: [
"Target Application": app?.bundleIdentifier as Any
])

self.priorKBLayout = InputSourceManager.currentInputSource()
if let forceKBLayout = self.forceKBLayout {
forceKBLayout.select()
Expand Down
14 changes: 14 additions & 0 deletions ViMac-Swift/ViewControllers/HintModeViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import AXSwift
import RxSwift
import Carbon.HIToolbox
import os
import Segment

struct Hint {
let element: Element
Expand Down Expand Up @@ -92,11 +93,18 @@ class HintModeViewController: ModeViewController, NSTextFieldDelegate {
let matchingHints = hints.filter { $0.text.starts(with: typed.uppercased()) }

if matchingHints.count == 0 && typed.count > 0 {
Analytics.shared().track("Hint Mode Deadend", properties: [
"Target Application": app?.bundleIdentifier as Any
])
self.modeCoordinator?.exitMode()
return
}

if matchingHints.count == 1 {
Analytics.shared().track("Hint Mode Action Performed", properties: [
"Target Application": app?.bundleIdentifier as Any
])

let hint = matchingHints.first!

// close the window before performing click(s)
Expand Down Expand Up @@ -162,6 +170,9 @@ class HintModeViewController: ModeViewController, NSTextFieldDelegate {

func observeEscKey() {
inputListener.observeEscapeKey(onEvent: { [weak self] _ in
Analytics.shared().track("Hint Mode Deactivated", properties: [
"Target Application": self?.app?.bundleIdentifier as Any
])
self?.onEscape()
})
}
Expand All @@ -178,6 +189,9 @@ class HintModeViewController: ModeViewController, NSTextFieldDelegate {

func observeSpaceKey() {
inputListener.observeSpaceKey(onEvent: { [weak self] _ in
Analytics.shared().track("Hint Mode Rotated Hints", properties: [
"Target Application": self?.app?.bundleIdentifier as Any
])
self?.rotateHints()
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import Cocoa
import RxSwift
import Segment

class ScrollModeActiveViewController: NSViewController {
private let scrollAreas: [Element]
Expand Down Expand Up @@ -52,6 +53,8 @@ class ScrollModeActiveViewController: NSViewController {
}

private func activateNextScrollArea() {
Analytics.shared().track("Scroll Mode Cycle Scroll Area")

activeScrollAreaIndex = (activeScrollAreaIndex + 1) % scrollAreas.count
setActiveScrollArea(activeScrollAreaIndex)
}
Expand Down
2 changes: 2 additions & 0 deletions ViMac-Swift/ViewControllers/ScrollModeViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import Cocoa
import RxSwift
import Segment

class ScrollModeViewController: ModeViewController {
private let disposeBag = DisposeBag()
Expand Down Expand Up @@ -62,6 +63,7 @@ class ScrollModeViewController: ModeViewController {
let escEvents = inputListener.keyDownEvents.filter { $0.keyCode == kVK_Escape }
return escEvents
.bind(onNext: { [weak self] _ in
Analytics.shared().track("Scroll Mode Deactivated")
self?.modeCoordinator?.exitMode()
})
}
Expand Down
42 changes: 42 additions & 0 deletions docs/metrics-collection.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Metrics Collection

As of v0.3.17 (28), Vimac collects usage metrics so that I (@dexterleng) can make data-informed decisions regarding the application going into the future.

I've written this document to be transparent about what data I'll be collecting and how they will be used.

## Usage Metrics Collected

Vimac reports the following events:

1. Hint Mode Activated/Deactivated/Action Performed/Hint Rotation
2. Scroll Mode Activated/Deactivated/Cycle Scroll Area

## What are the metrics collected used for?

### 1. Optimizing the Vimac workflow

Vimac is an application that aims to help you replace the mouse/trackpad with the keyboard. I would like to measure the retention rate (percentage of users that continue using Vimac after n-days). This would help in determining:

1. The difficulty users have replacing the mouse with the keyboard with Vimac
2. Whether a change I've made to the workflow has reduced that difficulty

### 2. Improving the algorithm for determining "hintability"

I've attached the target application's bundle identifier to events. This allows me to determine:

1. The common applications Vimac is used on
2. The applications Vimac do not work well on

Vimac's algorithm for determining whether an element is "hintable" is largely dependent on heuristics based on patterns I've observed in applications I've tested it on. Knowing about the popular target applications allows me to prioritize testing and improving the experience when using Vimac on those applications.

## What we will not track

Vimac will not report the contents of the screen that it has access to through the Accessibility API.

## Privacy

No login is required to use Vimac. Usage metrics are anonymous and the identity of the user cannot be determined.

## Can I disable usage metrics reporting?

No. I will make it optional in v1.
Binary file modified grant-accessibility-permission-dev.scpt
Binary file not shown.

0 comments on commit ff21f9c

Please sign in to comment.