Merge pull request #9441 from davidkelly/dk/makeUsSomeAnalytics

Some initial analytics for PAL usage
This commit is contained in:
Ryan Downe Karpf 2017-01-20 08:30:46 -08:00 committed by GitHub
commit 03851d4188
6 changed files with 55 additions and 7 deletions

View file

@ -346,7 +346,12 @@ Item {
maximumValue: 20.0 maximumValue: 20.0
stepSize: 5 stepSize: 5
updateValueWhileDragging: true updateValueWhileDragging: true
onValueChanged: updateGainFromQML(uuid, value) onValueChanged: updateGainFromQML(uuid, value, false)
onPressedChanged: {
if (!pressed) {
updateGainFromQML(uuid, value, true)
}
}
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onWheel: { onWheel: {
@ -360,7 +365,8 @@ Item {
mouse.accepted = false mouse.accepted = false
} }
onReleased: { onReleased: {
// Pass through to Slider // the above mouse.accepted seems to make this
// never get called, nonetheless...
mouse.accepted = false mouse.accepted = false
} }
} }
@ -382,12 +388,13 @@ Item {
} }
} }
function updateGainFromQML(avatarUuid, sliderValue) { function updateGainFromQML(avatarUuid, sliderValue, isReleased) {
if (pal.gainSliderValueDB[avatarUuid] !== sliderValue) { if (isReleased || pal.gainSliderValueDB[avatarUuid] !== sliderValue) {
pal.gainSliderValueDB[avatarUuid] = sliderValue; pal.gainSliderValueDB[avatarUuid] = sliderValue;
var data = { var data = {
sessionId: avatarUuid, sessionId: avatarUuid,
gain: sliderValue gain: sliderValue,
isReleased: isReleased
}; };
pal.sendToScript({method: 'updateGain', params: data}); pal.sendToScript({method: 'updateGain', params: data});
} }

View file

@ -250,6 +250,7 @@ Rectangle {
userModel.setProperty(model.userIndex, styleData.role, newValue) userModel.setProperty(model.userIndex, styleData.role, newValue)
userModelData[model.userIndex][styleData.role] = newValue // Defensive programming userModelData[model.userIndex][styleData.role] = newValue // Defensive programming
Users[styleData.role](model.sessionId, newValue) Users[styleData.role](model.sessionId, newValue)
UserActivityLogger["palAction"](newValue ? styleData.role : "un-" + styleData.role, model.sessionId)
if (styleData.role === "ignore") { if (styleData.role === "ignore") {
userModel.setProperty(model.userIndex, "personalMute", newValue) userModel.setProperty(model.userIndex, "personalMute", newValue)
userModelData[model.userIndex]["personalMute"] = newValue // Defensive programming userModelData[model.userIndex]["personalMute"] = newValue // Defensive programming
@ -276,6 +277,7 @@ Rectangle {
height: 24 height: 24
onClicked: { onClicked: {
Users[styleData.role](model.sessionId) Users[styleData.role](model.sessionId)
UserActivityLogger["palAction"](styleData.role, model.sessionId)
if (styleData.role === "kick") { if (styleData.role === "kick") {
// Just for now, while we cannot undo "Ban": // Just for now, while we cannot undo "Ban":
userModel.remove(model.userIndex) userModel.remove(model.userIndex)

View file

@ -1937,6 +1937,8 @@ void Application::initializeUi() {
rootContext->setContextProperty("AvatarList", DependencyManager::get<AvatarManager>().data()); rootContext->setContextProperty("AvatarList", DependencyManager::get<AvatarManager>().data());
rootContext->setContextProperty("Users", DependencyManager::get<UsersScriptingInterface>().data()); rootContext->setContextProperty("Users", DependencyManager::get<UsersScriptingInterface>().data());
rootContext->setContextProperty("UserActivityLogger", DependencyManager::get<UserActivityLoggerScriptingInterface>().data());
rootContext->setContextProperty("Camera", &_myCamera); rootContext->setContextProperty("Camera", &_myCamera);
#if defined(Q_OS_MAC) || defined(Q_OS_WIN) #if defined(Q_OS_MAC) || defined(Q_OS_WIN)

View file

@ -38,6 +38,21 @@ void UserActivityLoggerScriptingInterface::tutorialProgress( QString stepName, i
} }
void UserActivityLoggerScriptingInterface::palAction(QString action, QString target) {
QJsonObject payload;
payload["action"] = action;
if (target.length() > 0) {
payload["target"] = target;
}
logAction("pal_activity", payload);
}
void UserActivityLoggerScriptingInterface::palOpened(float secondsOpened) {
logAction("pal_opened", {
{ "seconds_opened", secondsOpened }
});
}
void UserActivityLoggerScriptingInterface::logAction(QString action, QJsonObject details) { void UserActivityLoggerScriptingInterface::logAction(QString action, QJsonObject details) {
QMetaObject::invokeMethod(&UserActivityLogger::getInstance(), "logAction", QMetaObject::invokeMethod(&UserActivityLogger::getInstance(), "logAction",
Q_ARG(QString, action), Q_ARG(QString, action),

View file

@ -25,7 +25,8 @@ public:
Q_INVOKABLE void toggledAway(bool isAway); Q_INVOKABLE void toggledAway(bool isAway);
Q_INVOKABLE void tutorialProgress(QString stepName, int stepNumber, float secondsToComplete, Q_INVOKABLE void tutorialProgress(QString stepName, int stepNumber, float secondsToComplete,
float tutorialElapsedTime, QString tutorialRunID = "", int tutorialVersion = 0, QString controllerType = ""); float tutorialElapsedTime, QString tutorialRunID = "", int tutorialVersion = 0, QString controllerType = "");
Q_INVOKABLE void palAction(QString action, QString target);
Q_INVOKABLE void palOpened(float secondsOpen);
private: private:
void logAction(QString action, QJsonObject details = {}); void logAction(QString action, QJsonObject details = {});
}; };

View file

@ -103,6 +103,8 @@ ExtendedOverlay.prototype.select = function (selected) {
return; return;
} }
UserActivityLogger.palAction(selected ? "avatar_selected" : "avatar_deselected", this.key);
this.editOverlay({color: color(selected, this.hovering, this.audioLevel)}); this.editOverlay({color: color(selected, this.hovering, this.audioLevel)});
if (this.model) { if (this.model) {
this.model.editOverlay({textures: textures(selected)}); this.model.editOverlay({textures: textures(selected)});
@ -232,14 +234,24 @@ pal.fromQml.connect(function (message) { // messages are {method, params}, like
case 'refresh': case 'refresh':
removeOverlays(); removeOverlays();
populateUserList(); populateUserList();
UserActivityLogger.palAction("refresh", "");
break; break;
case 'updateGain': case 'updateGain':
data = message.params; data = message.params;
Users.setAvatarGain(data['sessionId'], data['gain']); if (data['isReleased']) {
// isReleased=true happens once at the end of a cycle of dragging
// the slider about, but with same gain as last isReleased=false so
// we don't set the gain in that case, and only here do we want to
// send an analytic event.
UserActivityLogger.palAction("avatar_gain_changed", data['sessionId']);
} else {
Users.setAvatarGain(data['sessionId'], data['gain']);
}
break; break;
case 'displayNameUpdate': case 'displayNameUpdate':
if (MyAvatar.displayName != message.params) { if (MyAvatar.displayName != message.params) {
MyAvatar.displayName = message.params; MyAvatar.displayName = message.params;
UserActivityLogger.palAction("display_name_change", "");
} }
break; break;
default: default:
@ -552,7 +564,10 @@ var button = toolBar.addButton({
buttonState: 1, buttonState: 1,
alpha: 0.9 alpha: 0.9
}); });
var isWired = false; var isWired = false;
var palOpenedAt;
function off() { function off() {
if (isWired) { // It is not ok to disconnect these twice, hence guard. if (isWired) { // It is not ok to disconnect these twice, hence guard.
Script.update.disconnect(updateOverlays); Script.update.disconnect(updateOverlays);
@ -564,6 +579,11 @@ function off() {
triggerPressMapping.disable(); // see above triggerPressMapping.disable(); // see above
removeOverlays(); removeOverlays();
Users.requestsDomainListData = false; Users.requestsDomainListData = false;
if (palOpenedAt) {
var duration = new Date().getTime() - palOpenedAt;
UserActivityLogger.palOpened(duration / 1000.0);
palOpenedAt = 0; // just a falsy number is good enough.
}
if (audioInterval) { if (audioInterval) {
Script.clearInterval(audioInterval); Script.clearInterval(audioInterval);
} }
@ -580,6 +600,7 @@ function onClicked() {
triggerMapping.enable(); triggerMapping.enable();
triggerPressMapping.enable(); triggerPressMapping.enable();
createAudioInterval(); createAudioInterval();
palOpenedAt = new Date().getTime();
} else { } else {
off(); off();
} }