Author: smaisonneuve Date: 2015-04-29 12:16:59 +0000 (Wed, 29 Apr 2015) New Revision: 1294 Url: http://forge.nuiton.org/projects/sandbox/repository/revisions/1294 Log: [Wit] - Activity detection (basis) Added: wit/activityChange.html Modified: wit/js/main.js wit/js/services/TimerService.js wit/js/services/UserActivityService.js Copied: wit/activityChange.html (from rev 1283, wit/idle.html) =================================================================== --- wit/activityChange.html (rev 0) +++ wit/activityChange.html 2015-04-29 12:16:59 UTC (rev 1294) @@ -0,0 +1,55 @@ +<html> + <head> + <title>WIT idle</title> + <link rel="stylesheet" href="./node_modules/bootstrap/dist/css/bootstrap.min.css"> + + <style> + h1 { + text-align: center; + } + </style> + + <script> + var gui = require('nw.gui'); + var window = gui.Window.get(); + var timer = global.timer; + var user = global.user; + + var keepTiming = function() { + user.resumeActivityDetection(); + window.close(); + }; + var stopTiming = function() { + timer.stop(); + window.close(); + }; + var startNewActivity = function() { + timer.reassignTimeFrom(user.getActivityChangeDetectedDate()); + window.close(); + }; + + timer.subscribeIdle(window.close.bind(window)); + </script> + </head> + + <body> + <div class="container-fluid"> + <h1>Activity change detected</h1> + <div class="alert alert-danger" role="alert"> Are you still working on the same activity ?</div> + + <button type="button" class="btn btn-primary btn-lg btn-block" onclick="keepTiming()"> + <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> + Yes ! Please keep timing current activity + </button> + <button type="button" class="btn btn-primary btn-lg btn-block" onclick="stopTiming()"> + <span class="glyphicon glyphicon-minus" aria-hidden="true"></span> + No, stop the timer ! + </button> + <button type="button" class="btn btn-primary btn-lg btn-block" onclick="startNewActivity()"> + <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> + No, right, i would like to time a new activity. + </button> + </div> + </body> + +</html> Modified: wit/js/main.js =================================================================== --- wit/js/main.js 2015-04-29 10:05:58 UTC (rev 1293) +++ wit/js/main.js 2015-04-29 12:16:59 UTC (rev 1294) @@ -15,6 +15,8 @@ global.timer = timer; var user = require('./js/services/UserActivityService.js'); +global.user = user; + var config = require('./js/services/ConfigurationService.js'); var React = require('react'); @@ -101,13 +103,16 @@ React.render(<Handler/>, document.body); }); -timer.subscribeIdle(function() { +var popups = []; +var openWindow = function (file) { var gui = global.window.nwDispatcher.requireNwGui(); var current = gui.Window.get(); current.hide(); - var window = gui.Window.open('idle.html', { + user.suspendActivityDetection(); + + var window = gui.Window.open(file, { "position": "center", "focus": true, "toolbar": false, @@ -116,10 +121,21 @@ "height": 300, }); + popups.push(window); + window.on('close', function() { this.hide(); // Pretend to be closed already this.close(true); + + popups.splice(popups.indexOf(window), 1); - current.show(); - }); -}); + if (!popups.length) { + current.show(); + } + }); +}; + +// Subscriptions to services + +timer.subscribeIdle(openWindow.bind(null, "idle.html")) +user.subscribeActivityChange(openWindow.bind(null, "activityChange.html")); Modified: wit/js/services/TimerService.js =================================================================== --- wit/js/services/TimerService.js 2015-04-29 10:05:58 UTC (rev 1293) +++ wit/js/services/TimerService.js 2015-04-29 12:16:59 UTC (rev 1294) @@ -44,11 +44,13 @@ }; exports.start = function() { - time = idleTime || new Date(); + time = time || new Date(); idleTime = null; historyIndex = -1; timeChange(); + + user.resumeActivityDetection(); }; exports.stop = function(force) { @@ -126,6 +128,7 @@ }; exports.keepIdle = function() { + user.resumeActivityDetection(); idleTime = null; }; @@ -147,8 +150,12 @@ }; exports.reassignIdle = function() { - insertLog(tags, time, idleTime); - time = idleTime; + exports.reassignTimeFrom(idleTime); +}; + +exports.reassignTimeFrom = function (newStartTime) { + insertLog(tags, time, newStartTime); + time = newStartTime; clearTimeout(timeChangeTimer); eventEmitter.emit('onTimeChanged'); Modified: wit/js/services/UserActivityService.js =================================================================== --- wit/js/services/UserActivityService.js 2015-04-29 10:05:58 UTC (rev 1293) +++ wit/js/services/UserActivityService.js 2015-04-29 12:16:59 UTC (rev 1294) @@ -2,11 +2,22 @@ var xprop = require('xprop'); var moment = require('moment'); var db = require("./database.js"); +var config = require("./ConfigurationService.js"); +var events = require('events'); +var eventEmitter = new events.EventEmitter(); + var crtSession; +var activityChangeTimer; +var disableActivityDetection = false; const _NET_ACTIVE_WINDOW = 334; +/** + * Retrieve window activity sessions for the peridio [startDAte; endDate] + * If withEmptySession parameter equals true, then if there is a gap between 2 sessions in the results, + * it will be filled with a fake session + */ exports.getSessions = function (startDate, endDate, withEmptySession) { var rst; if (!startDate || !endDate) { @@ -58,9 +69,32 @@ return rst; } -/* Inspired by : -http://stackoverflow.com/questions/19840459/linux-get-notification-on-focuse... -*/ +/** + * Offers an api for services interesting in activity change detection + */ +exports.subscribeActivityChange = function(callback) { + eventEmitter.on('onActivityChange', callback); +}; + +exports.getActivityChangeDetectedDate = function () { + return activityChangeTimer && activityChangeTimer.changeDetectedDate; +}; + +exports.suspendActivityDetection = function () { + disableActivityDetection = true; + clearTimeout(activityChangeTimer); +}; + +exports.resumeActivityDetection = function () { + disableActivityDetection = false; +}; + +/* + * Listen to active window change and window title change + * Some part of the code has derived from : + * http://stackoverflow.com/questions/19840459/linux-get-notification-on-focuse... + * + */ x11.createClient(function(err, display) { var X = display.client; @@ -77,7 +111,20 @@ X.on('event', onActiveWindowChange.bind(null, X)); }); +/** + * Subscriber to timer change : + * If timer change occured while activity change detection is on going, + * stop activity change detection process (means the user has handled it) + */ +timer.subscribeTimeChanged(function () { + !timer.getTime() && clearTimeout(activityChangeTimer); +}); + +/////////////// +// Utilities // +/////////////// + var onActiveWindowChange = function (X, ev) { if(ev.name == 'PropertyNotify') { @@ -107,12 +154,23 @@ }); }; +/** + * Create a new window session + */ var addWindowSession = function (X, parentId) { + var crt = crtSession; + return getActiveWindowId(X, parentId) .then(getWindowName) - .then(createNewSession); + .then(createNewSession) + .then(setupActivityDetection.bind(null, crt)); }; +/** + * Current active window is still the same + * but it's title has changed. + * Trace it by creating a new session with the same shape attributes than the previous one + */ var updateWindowSession = function (wid) { return getWindowName(wid) .then(function (windowName) { @@ -165,6 +223,8 @@ var createNewSession = function (windowName, color, startDate) { var now = moment(); + // Stop current session + if (crtSession) { crtSession.endDate = now.valueOf(); db.insertSession(crtSession); @@ -175,6 +235,8 @@ var prev = db.getSessionByName(windowName); + // Create new session + crtSession = { name: windowName, color: color || prev && prev.color || "#" + (Math.floor(Math.random() * (999 - 100 + 1)) + 100), @@ -190,5 +252,36 @@ color: "transparent", startDate: d1, endDate: d2 + }; +}; + +var setupActivityDetection = function (session) { + if (disableActivityDetection || !session || !timer.getTime()) { + + clearTimeout(activityChangeTimer); // stop activity detection + + } else { + + now = moment(); + if (now.diff(session.startDate, "m") >= config.getActivityTime()) { + + // The user has stayed more than "config.getActivityTime()" minutes on a window + // and now has just switched to another window. + // If it stays at list as long as he did on the previous one, let's notify it to him + + activityChangeTimer = setTimeout( + eventEmitter.emit.bind(eventEmitter, 'onActivityChange', now.toDate()), + moment.duration(config.getActivityTime(), "m").as("ms") + ); + activityChangeTimer.crtActivityName = session.name; + activityChangeTimer.changeDetectedDate = now.toDate(); + + } else if (session.name == activityChangeTimer.crtActivityName) { + + // The user is back to the window from which we initiated the activity timer, + // it seems to indicate that he is still working on the same activity. Let's clear the timer. + + clearTimeout(activityChangeTimer); + } } -} \ No newline at end of file +}; \ No newline at end of file
participants (1)
-
smaisonneuveďź users.nuiton.org