summaryrefslogtreecommitdiff
path: root/addons/timer/static/src
diff options
context:
space:
mode:
authorOkan SUMER (osu) <osu@odoo.com>2020-02-05 16:15:29 +0100
committerYannick Tivisse <yti@odoo.com>2020-02-05 16:44:37 +0100
commite2b749fb7a441b4337c40cc856459e2e5f95b597 (patch)
treeca9de35d2674582ed440e2f28484bd5d9bcbef0e /addons/timer/static/src
parenta6d7c7b04a48669037e6568849a26571602386f6 (diff)
[ADD] timer: New mixin to record time on models
Purpose ======= The timer mechanism is already existing on timesheet. We would like to introduce it on helpdesk.ticket too, and probably on other models afterward. On the other hand, only one timer can be launched on a single timesheet currently, shared amongst the different users. This commit introduced a new mixin on which - Each user can launch a timer on each record of the models inheriting the mixin. - Launching a new timer on a record pauses the timer of the user that could be already running. - The mixin brings methods to start/stop/pause/resume the timer, that could be overridden to implement a specific behavior for the related model, for example create a timesheet entry. TaskID: 2149450
Diffstat (limited to 'addons/timer/static/src')
-rw-r--r--addons/timer/static/src/js/timer.js63
-rw-r--r--addons/timer/static/src/js/timer_mixin.js115
-rw-r--r--addons/timer/static/src/js/timer_toggle_button.js76
-rw-r--r--addons/timer/static/src/scss/timer_button.scss26
4 files changed, 280 insertions, 0 deletions
diff --git a/addons/timer/static/src/js/timer.js b/addons/timer/static/src/js/timer.js
new file mode 100644
index 00000000000..0042ebfaead
--- /dev/null
+++ b/addons/timer/static/src/js/timer.js
@@ -0,0 +1,63 @@
+odoo.define('timer.timer', function (require) {
+"use strict";
+
+var fieldRegistry = require('web.field_registry');
+var AbstractField = require('web.AbstractField');
+var Timer = require('timer.Timer');
+
+var TimerFieldWidget = AbstractField.extend({
+
+ /**
+ * @override
+ * @private
+ */
+ isSet: function () {
+ return true;
+ },
+ /**
+ * @override
+ * @private
+ */
+ _render: function () {
+ this._super.apply(this, arguments);
+ this._startTimeCounter();
+ },
+ /**
+ * @override
+ */
+ destroy: function () {
+ this._super.apply(this, arguments);
+ clearInterval(this.timer);
+ },
+ /**
+ * @private
+ */
+ _startTimeCounter: async function () {
+ if (this.record.data.timer_start) {
+ const serverTime = this.record.data.timer_pause || await this._getServerTime();
+ this.time = Timer.createTimer(0, this.record.data.timer_start, serverTime);
+ this.$el.text(this.time.toString());
+ this.timer = setInterval(() => {
+ if (this.record.data.timer_pause) {
+ clearInterval(this.timer);
+ } else {
+ this.time.addSecond();
+ this.$el.text(this.time.toString());
+ }
+ }, 1000);
+ } else if (!this.record.data.timer_pause){
+ clearInterval(this.timer);
+ }
+ },
+ _getServerTime: function () {
+ return this._rpc({
+ model: 'timer.timer',
+ method: 'get_server_time',
+ args: []
+ });
+ }
+});
+
+fieldRegistry.add('timer_timer', TimerFieldWidget);
+
+});
diff --git a/addons/timer/static/src/js/timer_mixin.js b/addons/timer/static/src/js/timer_mixin.js
new file mode 100644
index 00000000000..779d06dbe4a
--- /dev/null
+++ b/addons/timer/static/src/js/timer_mixin.js
@@ -0,0 +1,115 @@
+odoo.define('timer.Timer', function (require) {
+"use strict";
+
+ /**
+ * This class improves the timer display using the
+ * unit_amount field on account.analytic.line.
+ */
+ class Timer {
+ constructor(hours, minutes, seconds) {
+ this.hours = hours;
+ this.minutes = minutes;
+ this.seconds = seconds;
+ }
+
+ /**
+ * Convert float to time
+ * @param {number} float
+ */
+ static convertFloatToTime(float) {
+ if (float === 0) {
+ return new Timer(0, 0, 0);
+ }
+
+ let minutes = float % 1;
+ const hours = float - minutes;
+ minutes *= 60;
+
+ return new Timer(hours, Math.round(minutes), 0);
+ }
+
+ /**
+ * Create timer
+ * @param {number} unit_amount
+ * @param {String} timer_start
+ * @param {String} serverTime
+ */
+ static createTimer(unit_amount, timer_start, serverTime) {
+ const timer = this.convertFloatToTime(unit_amount);
+
+ timer.addTime(
+ moment.utc(
+ moment.utc(serverTime)
+ .diff(moment.utc(timer_start))
+ ).format("HH:mm:ss")
+ );
+
+ return timer;
+ }
+
+ addHours(hours) {
+ this.hours += hours;
+ }
+
+ addMinutes(minutes) {
+ minutes += this.minutes;
+
+ this.minutes = minutes % 60;
+ this.addHours(Math.floor(minutes / 60));
+ }
+
+ addSeconds(seconds) {
+ seconds += this.seconds;
+ this.seconds = seconds % 60;
+ this.addMinutes(Math.floor(seconds / 60));
+ }
+
+ display2digits(number) {
+ return number > 9 ? "" + number : "0" + number;
+ }
+
+ addSecond() {
+ this.seconds += 1;
+ if (this.seconds === 60) {
+ this.minutes += 1;
+ this.seconds = 0;
+
+ if (this.minutes === 60) {
+ this.hours += 1;
+ this.minutes = 0;
+ }
+ }
+ }
+
+ addTime(time) {
+ if (typeof time == 'string' && time.indexOf(':') !== -1) {
+ let [hour, minute, second] = time.split(':');
+
+ hour = parseInt(hour);
+ minute = parseInt(minute);
+ second = parseInt(second);
+
+ this.addSeconds(second);
+ this.addMinutes(minute);
+ this.addHours(hour);
+ }
+ }
+
+ convertToFloat() {
+ return (this.hours * 60 + this.minutes) * 60 / 3600;
+ }
+
+ toString() {
+ const time = {
+ hours: this.display2digits(this.hours),
+ minutes: this.display2digits(this.minutes),
+ seconds: this.display2digits(this.seconds)
+ };
+
+ return `${time.hours}:${time.minutes}:${time.seconds}`;
+ }
+ }
+
+ return Timer;
+
+});
diff --git a/addons/timer/static/src/js/timer_toggle_button.js b/addons/timer/static/src/js/timer_toggle_button.js
new file mode 100644
index 00000000000..544c6219940
--- /dev/null
+++ b/addons/timer/static/src/js/timer_toggle_button.js
@@ -0,0 +1,76 @@
+odoo.define('timer.timer_toggle_button', function (require) {
+"use strict";
+
+const fieldRegistry = require('web.field_registry');
+const { FieldToggleBoolean } = require("web.basic_fields");
+
+/**
+ * The TimerToggleButton is used to display correctly the button
+ * to start or stop a timer for a timesheet in kanban, list and grid
+ * views.
+ */
+const TimerToggleButton = FieldToggleBoolean.extend({
+ /**
+ * @override
+ * @private
+ */
+ _render: function () {
+ // When the is_timer_running field is false, then the button is used to start the timer
+ const title = this.value ? 'stop' : 'play';
+ const name = this.value ? 'action_timer_stop' : 'action_timer_start';
+ const label = this.value ? 'stop' : 'start';
+
+ this.$('i')
+ .addClass('fa')
+ .toggleClass('fa-stop-circle o-timer-stop-button', this.value)
+ .toggleClass('fa-play-circle o-timer-play-button', !this.value)
+ .attr('title', title);
+
+ this.$el.addClass('o-timer-button');
+ this.$el.attr('title', title);
+ this.$el.attr('name', name);
+ this.$el.attr('aria-label', label);
+ this.$el.attr('aria-pressed', this.value);
+ this.$el.attr('type', 'button');
+ this.$el.attr('role', 'button');
+ },
+ /**
+ * Toggle the button
+ *
+ * When the user click on this button,
+ * - the action "action_timer_start" is called
+ * into the account.analytic.line model,
+ * if the value of is_timer_running field is set on false.
+ * - the action "action_timer_stop" is called
+ * into the account.analytic.line model,
+ * if the value of is_timer_running field is set on true.
+ * Then we change the value of the is_timer_running.
+ * @override
+ * @private
+ * @param {MouseEvent} event
+ */
+ _onToggleButton: async function (event) {
+ event.stopPropagation();
+ const result = await this._rpc({
+ model: this.model,
+ method: this._getActionButton(),
+ args: [this.res_id]
+ });
+
+ this.trigger_up('timer_changed', {
+ id: this.res_id,
+ is_timer_running: !this.value
+ });
+
+ this._setValue(!this.value);
+ },
+ _getActionButton: function () {
+ return this.value ? 'action_timer_stop' : 'action_timer_start';
+ }
+});
+
+fieldRegistry.add('timer_toggle_button', TimerToggleButton);
+
+return TimerToggleButton;
+
+});
diff --git a/addons/timer/static/src/scss/timer_button.scss b/addons/timer/static/src/scss/timer_button.scss
new file mode 100644
index 00000000000..8b269fa8b20
--- /dev/null
+++ b/addons/timer/static/src/scss/timer_button.scss
@@ -0,0 +1,26 @@
+.o-timer-button {
+ &:focus {
+ border: none !important;
+ outline: 0 !important;
+ }
+
+ & > i {
+ transition: 0.3s;
+
+ &.o-timer-play-button {
+ color: $link-color !important;
+ }
+
+ &.o-timer-stop-button {
+ color: $red !important;
+ }
+ }
+
+ &:hover > i.o-timer-play-button {
+ color: $link-hover-color !important;
+ }
+
+ &:hover > i.o-timer-stop-button {
+ color: darken($red, 15%) !important;
+ }
+}