diff options
-rw-r--r-- | src/org/traccar/database/ConnectionManager.java | 35 | ||||
-rw-r--r-- | web/app.css | 10 | ||||
-rw-r--r-- | web/app/Style.js | 6 | ||||
-rw-r--r-- | web/app/controller/Root.js | 21 | ||||
-rw-r--r-- | web/app/model/Device.js | 6 | ||||
-rw-r--r-- | web/app/view/Devices.js | 23 | ||||
-rw-r--r-- | web/app/view/MapController.js | 55 | ||||
-rw-r--r-- | web/l10n/en.json | 1 | ||||
-rw-r--r-- | web/l10n/no.json | 79 | ||||
-rw-r--r-- | web/l10n/si.json | 16 | ||||
-rw-r--r-- | web/locale.js | 1 |
11 files changed, 229 insertions, 24 deletions
diff --git a/src/org/traccar/database/ConnectionManager.java b/src/org/traccar/database/ConnectionManager.java index 345bb4577..ae931151d 100644 --- a/src/org/traccar/database/ConnectionManager.java +++ b/src/org/traccar/database/ConnectionManager.java @@ -25,8 +25,13 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.TimeUnit; + import org.jboss.netty.channel.Channel; +import org.jboss.netty.util.Timeout; +import org.jboss.netty.util.TimerTask; import org.traccar.Context; +import org.traccar.GlobalTimer; import org.traccar.Protocol; import org.traccar.helper.Log; import org.traccar.model.Device; @@ -34,11 +39,17 @@ import org.traccar.model.Position; public class ConnectionManager { + private static final long DEFAULT_TIMEOUT = 600; + + private final long deviceTimeout; + private final Map<Long, ActiveDevice> activeDevices = new HashMap<>(); private final Map<Long, Position> positions = new HashMap<>(); private final Map<Long, Set<UpdateListener>> listeners = new HashMap<>(); + private final Map<Long, Timeout> timeouts = new HashMap<>(); public ConnectionManager(DataManager dataManager) { + deviceTimeout = Context.getConfig().getLong("status.timeout", DEFAULT_TIMEOUT) * 1000; if (dataManager != null) { try { for (Position position : dataManager.getLatestPositions()) { @@ -57,7 +68,7 @@ public class ConnectionManager { public void removeActiveDevice(Channel channel) { for (ActiveDevice activeDevice : activeDevices.values()) { if (activeDevice.getChannel() == channel) { - updateDevice(activeDevice.getDeviceId(), Device.STATUS_OFFLINE, new Date()); + updateDevice(activeDevice.getDeviceId(), Device.STATUS_OFFLINE, null); activeDevices.remove(activeDevice.getDeviceId()); break; } @@ -68,10 +79,28 @@ public class ConnectionManager { return activeDevices.get(deviceId); } - public synchronized void updateDevice(long deviceId, String status, Date time) { + public synchronized void updateDevice(final long deviceId, String status, Date time) { Device device = Context.getIdentityManager().getDeviceById(deviceId); device.setStatus(status); - device.setLastUpdate(time); + if (time != null) { + device.setLastUpdate(time); + } + + Timeout timeout = timeouts.remove(deviceId); + if (timeout != null) { + timeout.cancel(); + } + + if (status.equals(Device.STATUS_ONLINE)) { + timeouts.put(deviceId, GlobalTimer.getTimer().newTimeout(new TimerTask() { + @Override + public void run(Timeout timeout) throws Exception { + if (!timeout.isCancelled()) { + updateDevice(deviceId, Device.STATUS_UNKNOWN, null); + } + } + }, deviceTimeout, TimeUnit.MILLISECONDS)); + } try { Context.getDataManager().updateDeviceStatus(device); diff --git a/web/app.css b/web/app.css index 3c4507e38..eb0fdf136 100644 --- a/web/app.css +++ b/web/app.css @@ -1,3 +1,13 @@ +.status-color-online { + background-color: rgba(77, 250, 144, 0.3); +} +.status-color-unknown { + background-color: rgba(250, 190, 77, 0.3); +} +.status-color-offline { + background-color: rgba(255, 84, 104, 0.3); +} + .state-indicator { position: absolute; top: -999em; diff --git a/web/app/Style.js b/web/app/Style.js index 58ab059ad..b75503c32 100644 --- a/web/app/Style.js +++ b/web/app/Style.js @@ -48,9 +48,9 @@ Ext.define('Traccar.Style', { mapTextOffset: 10, mapTextFont: 'bold 12px sans-serif', - mapColorOnline: '#4DFA90', - mapColorUnknown: '#FABE4D', - mapColorOffline: '#FF5468', + mapColorOnline: 'rgba(77, 250, 144, 1.0)', + mapColorUnknown: 'rgba(250, 190, 77, 1.0)', + mapColorOffline: 'rgba(255, 84, 104, 1.0)', mapColorReport: 'rgba(21, 127, 204, 1.0)', mapRadiusNormal: 10, diff --git a/web/app/controller/Root.js b/web/app/controller/Root.js index 041e0b902..733055cdf 100644 --- a/web/app/controller/Root.js +++ b/web/app/controller/Root.js @@ -97,19 +97,32 @@ Ext.define('Traccar.controller.Root', { first: first }, callback: Traccar.app.getErrorHandler(this, function (options, success, response) { - var i, store, data, devices, positions, position; + var i, deviceStore, positionStore, data, devices, positions, device, position; if (success) { - store = Ext.getStore('LatestPositions'); + deviceStore = Ext.getStore('Devices'); + positionStore = Ext.getStore('LatestPositions'); data = Ext.decode(response.responseText).data; devices = data.devices; positions = data.positions; + for (i = 0; i < devices.length; i++) { + device = deviceStore.findRecord('id', devices[i].id, 0, false, false, true); + if (device) { + device.set({ + status: devices[i].status, + lastUpdate: devices[i].lastUpdate + }, { + dirty: false + }); + } + } + for (i = 0; i < positions.length; i++) { - position = store.findRecord('deviceId', positions[i].deviceId, 0, false, false, true); + position = positionStore.findRecord('deviceId', positions[i].deviceId, 0, false, false, true); if (position) { position.set(positions[i]); } else { - store.add(Ext.create('Traccar.model.Position', positions[i])); + positionStore.add(Ext.create('Traccar.model.Position', positions[i])); } } diff --git a/web/app/model/Device.js b/web/app/model/Device.js index e9ed1f680..983e3e62e 100644 --- a/web/app/model/Device.js +++ b/web/app/model/Device.js @@ -27,5 +27,11 @@ Ext.define('Traccar.model.Device', { }, { name: 'uniqueId', type: 'string' + }, { + name: 'status', + type: 'string' + }, { + name: 'lastUpdate', + type: 'date' }] }); diff --git a/web/app/view/Devices.js b/web/app/view/Devices.js index 9dcd76a55..128cd3be1 100644 --- a/web/app/view/Devices.js +++ b/web/app/view/Devices.js @@ -52,10 +52,27 @@ Ext.define('Traccar.view.Devices', { columns: [{ text: Strings.deviceName, - dataIndex: 'name', flex: 1 + dataIndex: 'name', + flex: 1 }, { - text: Strings.deviceIdentifier, - dataIndex: 'uniqueId', flex: 1 + text: Strings.deviceLastUpdate, + dataIndex: 'lastUpdate', + flex: 1, + renderer: function (value, metaData, record) { + var status = record.get('status'); + switch (status) { + case 'online': + metaData.tdCls = 'status-color-online'; + break; + case 'offline': + metaData.tdCls = 'status-color-offline'; + break; + default: + metaData.tdCls = 'status-color-unknown'; + break; + } + return Ext.Date.format(value, Traccar.Style.dateTimeFormat); + } }] }); diff --git a/web/app/view/MapController.js b/web/app/view/MapController.js index c153ebd45..95ceb51c3 100644 --- a/web/app/view/MapController.js +++ b/web/app/view/MapController.js @@ -27,6 +27,10 @@ Ext.define('Traccar.view.MapController', { } }, store: { + '#Devices': { + add: 'updateDevice', + update: 'updateDevice' + }, '#LatestPositions': { add: 'updateLatest', update: 'updateLatest' @@ -49,6 +53,51 @@ Ext.define('Traccar.view.MapController', { this.reportMarkers = {}; }, + getDeviceColor: function (device) { + console.log(device.get('status')); + switch (device.get('status')) { + case 'online': + return Traccar.Style.mapColorOnline; + case 'offline': + return Traccar.Style.mapColorOffline; + default: + return Traccar.Style.mapColorUnknown; + } + }, + + changeMarkerColor: function (style, color) { + return new ol.style.Style({ + image: new ol.style.Arrow({ + radius: style.getImage().getRadius(), + fill: new ol.style.Fill({ + color: color + }), + stroke: style.getImage().getStroke(), + rotation: style.getImage().getRotation() + }), + text: style.getText() + }); + }, + + updateDevice: function (store, data) { + var i, device, deviceId; + + if (!Ext.isArray(data)) { + data = [data]; + } + + for (i = 0; i < data.length; i++) { + device = data[i]; + deviceId = device.get('id'); + + if (deviceId in this.latestMarkers) { + marker = this.latestMarkers[deviceId]; + marker.setStyle( + this.changeMarkerColor(marker.getStyle(), this.getDeviceColor(device))); + } + } + }, + updateLatest: function (store, data) { var i, position, geometry, device, deviceId, marker, style; @@ -75,7 +124,7 @@ Ext.define('Traccar.view.MapController', { this.latestMarkers[deviceId] = marker; this.getView().getVectorSource().addFeature(marker); - style = this.getLatestMarker(); + style = this.getLatestMarker(this.getDeviceColor(device)); style.getText().setText(device.get('name')); marker.setStyle(style); } @@ -175,9 +224,9 @@ Ext.define('Traccar.view.MapController', { }); }, - getLatestMarker: function () { + getLatestMarker: function (color) { return this.getMarkerStyle( - Traccar.Style.mapRadiusNormal, Traccar.Style.mapColorUnknown); + Traccar.Style.mapRadiusNormal, color); }, getReportMarker: function () { diff --git a/web/l10n/en.json b/web/l10n/en.json index a3489fbe1..b18c85afd 100644 --- a/web/l10n/en.json +++ b/web/l10n/en.json @@ -31,6 +31,7 @@ "deviceTitle": "Devices", "deviceName": "Name", "deviceIdentifier": "Identifier", + "deviceLastUpdate": "Last Update", "deviceCommand": "Command", "settingsTitle": "Settings", "settingsUser": "Account", diff --git a/web/l10n/no.json b/web/l10n/no.json new file mode 100644 index 000000000..8a53e1213 --- /dev/null +++ b/web/l10n/no.json @@ -0,0 +1,79 @@ +{ + "sharedLoading": "Laster...", + "sharedSave": "Lagre", + "sharedCancel": "Avbryte", + "sharedAdd": "Legg til", + "sharedEdit": "Endre", + "sharedRemove": "Fjerne", + "sharedRemoveConfirm": "Fjerne element?", + "sharedKm": "km", + "sharedMi": "mi", + "sharedKmh": "km/t", + "sharedMph": "mph", + "sharedHour": "Time", + "sharedMinute": "Minutt", + "sharedSecond": "Sekund", + "errorTitle": "Feil", + "errorUnknown": "Ukjent feil", + "errorConnection": "Forbindelse feilet", + "userName": "Navn", + "userEmail": "Epost", + "userPassword": "Passord", + "userAdmin": "Admin", + "loginTitle": "Logg inn", + "loginLanguage": "Språk", + "loginRegister": "Registrere", + "loginLogin": "Logg inn", + "loginFailed": "Feil epost eller passord", + "loginCreated": "Ny bruker har blitt registrert", + "loginLogout": "Logg ut", + "deviceDialog": "Enhet", + "deviceTitle": "Enheter", + "deviceName": "Navn", + "deviceIdentifier": "Identitet", + "deviceCommand": "Kommando", + "settingsTitle": "Innstillinger", + "settingsUser": "Konto", + "settingsServer": "Server", + "settingsUsers": "Brukere", + "settingsDistanceUnit": "Avstand", + "settingsSpeedUnit": "Hastighet", + "reportTitle": "Rapporter", + "reportDevice": "Enhet", + "reportFrom": "Fra", + "reportTo": "Til", + "reportShow": "Vis", + "reportClear": "Nullstille", + "positionFixTime": "Tid", + "positionValid": "Gyldig", + "positionLatitude": "Latitude", + "positionLongitude": "Longitude", + "positionAltitude": "Altitude", + "positionSpeed": "Hastighet", + "positionCourse": "Retning", + "positionAddress": "Adresse", + "positionProtocol": "Protokoll", + "serverTitle": "Server Instillinger", + "serverZoom": "Zoom", + "serverRegistration": "Registere", + "mapTitle": "Kart", + "mapLayer": "Kart Lag", + "mapCustom": "Egendefinert Kart", + "mapOsm": "Open Street Kart", + "mapBingKey": "Bing Maps Nøkkel", + "mapBingRoad": "Bing Maps Vei", + "mapBingAerial": "Bing Maps Fly", + "stateTitle": "Stat", + "stateName": "Egenskap", + "stateValue": "Verdi", + "commandTitle": "Kommando", + "commandSend": "Sende", + "commandType": "Type", + "commandSent": "Kommando har blitt sendt", + "commandPositionPeriodic": "Periodisk Rapportering", + "commandPositionStop": "Stoppe Rapportering", + "commandEngineStop": "Motor Stop", + "commandEngineResume": "Motor Restarte", + "commandFrequency": "Frekvens", + "commandUnit": "Enhet" +}
\ No newline at end of file diff --git a/web/l10n/si.json b/web/l10n/si.json index 8e565423b..db6381586 100644 --- a/web/l10n/si.json +++ b/web/l10n/si.json @@ -1,5 +1,5 @@ { - "sharedLoading": "පූරණය ...", + "sharedLoading": "පූරණය කරමින් ...", "sharedSave": "සුරකින්න", "sharedCancel": "අවලංගු කරන්න", "sharedAdd": "එක් කරන්න", @@ -13,19 +13,19 @@ "sharedHour": "පැය", "sharedMinute": "මිනිත්තු", "sharedSecond": "තත්පර", - "errorTitle": "දෝෂයක්", - "errorUnknown": "නොදන්නා දෝෂයක්", - "errorConnection": "සම්බන්ධතා දෝෂයක්", + "errorTitle": "දෝෂයක් ", + "errorUnknown": "නොදන්නා දෝෂයක් !", + "errorConnection": "සම්බන්ධතා දෝෂයක් !", "userName": "නම", "userEmail": "විද්යුත් තැපෑල", "userPassword": "මුරපදය", "userAdmin": "පරිපාලක", - "loginTitle": "පිවිසුම", + "loginTitle": "පිවිසුම් ගිණුම", "loginLanguage": "භාෂාව", "loginRegister": "ලියාපදිංචි කරන්න", "loginLogin": "පිවිසුම", - "loginFailed": "ඊ-මේල් ලිපිනය හෝ මුරපදය වැරදිය", - "loginCreated": "නව පරිශීලක ලියාපදිංචි කරන ලදි", + "loginFailed": "ඊ-මේල් ලිපිනය හෝ මුරපදය වැරදිය !", + "loginCreated": "නව පරිශීලක ලියාපදිංචි කරන ලදි !", "loginLogout": "ඉවත්වන්න", "deviceDialog": "උපාංගය", "deviceTitle": "උපාංග", @@ -69,7 +69,7 @@ "commandTitle": "විධානය", "commandSend": "යවන්න", "commandType": "වර්ගය", - "commandSent": "අණ යවා ඇත", + "commandSent": "විධානය යවා ඇත", "commandPositionPeriodic": "ආවර්තිතව වාර්තා කරන්න", "commandPositionStop": "වාර්තා කිරීම නවත්වන්න", "commandEngineStop": "එන්ජිම නවත්වන්න", diff --git a/web/locale.js b/web/locale.js index a5acb0ad3..8b050c6f8 100644 --- a/web/locale.js +++ b/web/locale.js @@ -33,6 +33,7 @@ Locale.languages = { 'hu': { name: 'Magyar', code: 'hu' }, 'lt': { name: 'Lietuvių', code: 'lt' }, 'nl': { name: 'Nederlands', code: 'nl' }, + 'no': { name: 'Norsk', code: 'no_NB' }, 'pl': { name: 'Polski', code: 'pl' }, 'pt': { name: 'Português', code: 'pt' }, 'pt_BR': { name: 'Português (Brasil)', code: 'pt_BR' }, |