1
0
Fork 0
mirror of https://github.com/openstf/stf synced 2025-10-04 10:19:30 +02:00

Save user settings to the database and embed them to the template for fast access.

This commit is contained in:
Simo Kinnunen 2014-07-04 22:59:29 +09:00
parent 332c7b6106
commit e13fc6701f
11 changed files with 152 additions and 141 deletions

View file

@ -13,7 +13,6 @@
"oboe": "~1.15.1", "oboe": "~1.15.1",
"fa-borderlayout": "~0.3.1-beta2", "fa-borderlayout": "~0.3.1-beta2",
"Snap.svg": "~0.3.0", "Snap.svg": "~0.3.0",
"angular-localForage": "~0.2.6",
"ng-table": "git://github.com/esvit/ng-table.git#bd9ec42172389257fcd312330013302b2696ac2a", "ng-table": "git://github.com/esvit/ng-table.git#bd9ec42172389257fcd312330013302b2696ac2a",
"jquery.terminal": "~0.8.7", "jquery.terminal": "~0.8.7",
"stf-site": "~0.4.1", "stf-site": "~0.4.1",

View file

@ -25,6 +25,7 @@ dbapi.saveUserAfterLogin = function(user) {
, lastLoggedInAt: r.now() , lastLoggedInAt: r.now()
, createdAt: r.now() , createdAt: r.now()
, forwards: [] , forwards: []
, settings: {}
})) }))
} }
return stats return stats
@ -35,6 +36,18 @@ dbapi.loadUser = function(email) {
return db.run(r.table('users').get(email)) return db.run(r.table('users').get(email))
} }
dbapi.updateUserSettings = function(email, changes) {
return db.run(r.table('users').get(email).update({
settings: changes
}))
}
dbapi.resetUserSettings = function(email) {
return db.run(r.table('users').get(email).update({
settings: r.literal({})
}))
}
dbapi.addUserForward = function(email, forward) { dbapi.addUserForward = function(email, forward) {
var devicePort = forward.devicePort var devicePort = forward.devicePort
return db.run(r.table('users').get(email).update({ return db.run(r.table('users').get(email).update({

View file

@ -256,6 +256,13 @@ module.exports = function(options) {
new Promise(function(resolve) { new Promise(function(resolve) {
socket.on('disconnect', resolve) socket.on('disconnect', resolve)
// Settings
.on('user.settings.update', function(data) {
dbapi.updateUserSettings(user.email, data)
})
.on('user.settings.reset', function() {
dbapi.resetUserSettings(user.email)
})
// Touch events // Touch events
.on('input.touchDown', createTouchHandler(wire.TouchDownMessage)) .on('input.touchDown', createTouchHandler(wire.TouchDownMessage))
.on('input.touchMove', createTouchHandler(wire.TouchMoveMessage)) .on('input.touchMove', createTouchHandler(wire.TouchMoveMessage))

View file

@ -1,17 +1,2 @@
require('localforage') module.exports = angular.module('stf/settings', [])
require('angular-localForage')
module.exports = angular.module('stf/settings', [
'LocalForageModule'
])
.config(['$localForageProvider', function ($localForageProvider) {
$localForageProvider.config({
driver: 'localStorageWrapper',
name: 'stf-v0',
version: 1.0,
storeName: 'settings',
description: 'STF Local Settings'
})
}])
.factory('SettingsService', require('./settings-service')) .factory('SettingsService', require('./settings-service'))

View file

@ -1,61 +1,103 @@
var Promise = require('bluebird') var _ = require('lodash')
module.exports = function SettingsServiceFactory($localForage) { module.exports = function SettingsServiceFactory(
$rootScope
, UserService
, socket
) {
var SettingsService = {} var SettingsService = {}
var loadedInMemory = false var settings = UserService.currentUser.settings || {}
, syncListeners = []
var memoryData = Object.create(null) function createListener(object, options, monitor) {
var source = options.source || options.target
return function() {
var value = object[options.target] = (source in settings)
? settings[source]
: options.defaultValue
function setItemMemory(key, value) { if (monitor) {
memoryData[key] = value monitor(value)
}
}
} }
function getItemMemory(key) { function applyDelta(delta) {
return memoryData[key] $rootScope.safeApply(function() {
} _.merge(settings, delta, function(a, b) {
// New Arrays overwrite old Arrays
return _.isArray(b) ? b : undefined
})
SettingsService.setItem = function (key, value) { for (var i = 0, l = syncListeners.length; i < l; ++i) {
setItemMemory(key, value) syncListeners[i]()
return $localForage.setItem(key, value)
} }
function loadAllItems() {
if (loadedInMemory) {
return Promise.resolve()
}
return $localForage.getKeys().then(function (keys) {
return Promise.all(keys.map(function (key) {
return $localForage.getItem(key).then(setItemMemory.bind(null, key))
}))
}).then(function () {
loadedInMemory = true
}) })
} }
SettingsService.getItem = function (key) { SettingsService.update = function(delta) {
return loadAllItems().then(function () { socket.emit('user.settings.update', delta)
return getItemMemory(key) applyDelta(delta)
})
} }
SettingsService.bind = function () { SettingsService.set = function(key, value) {
var delta = Object.create(null)
delta[key] = value
SettingsService.update(delta)
return $localForage.bind.apply($localForage, arguments)
} }
SettingsService.driver = function () { SettingsService.reset = function() {
return $localForage.driver.apply($localForage, arguments) socket.emit('user.settings.reset')
+ ' with memory cache' settings = {}
applyDelta(null)
} }
SettingsService.clear = function () { SettingsService.bind = function(scope, options) {
memoryData = Object.create(null) var source = options.source || options.target
return $localForage.clear.apply($localForage, arguments)
scope.$watch(
options.target
, function(newValue, oldValue) {
// Skip initial value.
if (newValue !== oldValue) {
var delta = Object.create(null)
delta[source] = newValue
SettingsService.update(delta)
} }
}
, true
)
scope.$watch(
function() {
return settings[source]
}
, function(newValue, oldValue) {
// Skip initial value. The new value might not be different if
// settings were reset, for example. In that case we call back
// to the default value.
if (newValue !== oldValue) {
scope[options.target] = newValue || options.defaultValue
}
}
, true
)
scope[options.target] = settings[source] || options.defaultValue
}
SettingsService.sync = function(object, options, monitor) {
var listener = createListener(object, options, monitor)
listener() // Initialize
return syncListeners.push(listener) - 1
}
SettingsService.unsync = function(id) {
syncListeners.splice(id, 1)
}
socket.on('user.settings.update', applyDelta)
return SettingsService return SettingsService
} }

View file

@ -1,3 +1,3 @@
module.exports = function LayoutCtrl(LanguageService) { module.exports = function LayoutCtrl(LanguageService) {
LanguageService.init() LanguageService.updateLanguage()
} }

View file

@ -1,8 +1,13 @@
module.exports = function MenuCtrl($scope, $rootScope, SettingsService, $location, ExternalUrlModalService) { module.exports = function MenuCtrl(
$rootScope.platform = 'native' $scope
, $rootScope
, SettingsService
, $location
, ExternalUrlModalService
) {
SettingsService.bind($rootScope, { SettingsService.bind($rootScope, {
key: 'platform', target: 'platform'
storeName: 'Platform' , defaultValue: 'native'
}) })
$scope.$on('$routeChangeSuccess', function () { $scope.$on('$routeChangeSuccess', function () {

View file

@ -1,20 +1,8 @@
module.exports = function ($scope, LanguageService, SettingsService) { module.exports = function ($scope, LanguageService, SettingsService) {
// SettingsService.sync($scope, 'Language', { SettingsService.bind($scope, {
// language: LanguageService.detectedLanguage target: 'language'
// }) , source: LanguageService.settingKey
// SettingsService.bind($scope, { , defaultValue: LanguageService.detectedLanguage
// key: 'language',
// defaultValue: LanguageService.selectedLanguage
// })
LanguageService.getSelectedLanguage().then(function (data) {
$scope.language = data
})
$scope.$watch('language', function (newValue, oldValue) {
if (newValue !== oldValue) {
LanguageService.setSelectedLanguage(newValue)
}
}) })
$scope.supportedLanguages = LanguageService.supportedLanguages $scope.supportedLanguages = LanguageService.supportedLanguages

View file

@ -1,67 +1,45 @@
var _ = require('lodash')
var supportedLanguages = require('./../../../common/lang/langs.json') var supportedLanguages = require('./../../../common/lang/langs.json')
module.exports = function (SettingsService, $q, gettextCatalog) { module.exports = function LanguageServiceFactory(
SettingsService
, gettextCatalog
) {
var LanguageService = {} var LanguageService = {}
function detectLanguage() {
return (navigator.language || navigator.userLanguage || 'en-US')
.substring(0, 2)
}
function isSupported(lang) {
return !!supportedLanguages[lang]
}
function onlySupported(lang, defaultValue) {
return isSupported(lang) ? lang : defaultValue
}
LanguageService.settingKey = 'selectedLanguage'
LanguageService.supportedLanguages = supportedLanguages LanguageService.supportedLanguages = supportedLanguages
LanguageService.defaultLanguage = 'en'
LanguageService.detectedLanguage =
onlySupported(detectLanguage(), LanguageService.defaultLanguage)
var browserLocale = navigator.language || navigator.userLanguage || 'en-US' SettingsService.sync(
var browserLanguage = browserLocale.substring(0, 2) LanguageService
var isLanguageMatched = _.some(supportedLanguages, function (value, key) { , {
return key === browserLanguage target: LanguageService.settingKey
}) , source: LanguageService.settingKey
var detectedLanguage = isLanguageMatched ? browserLanguage : 'en' , defaultValue: LanguageService.detectedLanguage
var defaultLanguage = 'ja'
LanguageService.detectedLanguage = defaultLanguage
LanguageService.selectedLanguage = null
// TODO: Can't this be refactored to something like this?
// SettingsService.sync(LanguageService.selectedLanguage, 'Language', {
// selected: LanguageService.detectedLanguage
// })
LanguageService.getSelectedLanguage = function () {
var deferred = $q.defer()
if (LanguageService.selectedLanguage) {
deferred.resolve(LanguageService.selectedLanguage)
} else {
SettingsService.getItem('Language.selected').then(function (data) {
if (data) {
deferred.resolve(data)
} else {
LanguageService.setSelectedLanguage(LanguageService.detectedLanguage)
.then(function () {
deferred.resolve(LanguageService.detectedLanguage)
})
} }
}) , updateLanguage
} )
return deferred.promise
function updateLanguage() {
gettextCatalog.currentLanguage = LanguageService.selectedLanguage
} }
// TODO: this is to prevent initial text flashing from ja LanguageService.updateLanguage = updateLanguage
gettextCatalog.currentLanguage = LanguageService.detectedLanguage
// Initialize gettextCatalog
LanguageService.init = function () {
LanguageService.getSelectedLanguage().then(function (data) {
LanguageService.setSelectedLanguage(data)
})
}
LanguageService.setSelectedLanguage = function (lang) {
var deferred = $q.defer()
LanguageService.selectedLanguage = lang
gettextCatalog.currentLanguage = lang
SettingsService.setItem('Language.selected', lang).then(function () {
deferred.resolve(lang)
})
return deferred.promise
}
return LanguageService return LanguageService
} }

View file

@ -1,12 +1,9 @@
module.exports = function ($scope, SettingsService) { module.exports = function ($scope, SettingsService) {
$scope.resetSettings = function () { $scope.resetSettings = function () {
SettingsService.clear() SettingsService.reset()
console.log('Settings cleared') console.log('Settings cleared')
} }
$scope.savedTo = SettingsService.driver()
// $scope.resetSettings = function () { // $scope.resetSettings = function () {
// var title = 'Reset Settings'; // var title = 'Reset Settings';
// var msg = 'Are you sure you want to revert all settings to ' + // var msg = 'Are you sure you want to revert all settings to ' +

View file

@ -6,6 +6,3 @@
button(ng-click='resetSettings()').btn.btn-danger button(ng-click='resetSettings()').btn.btn-danger
i.fa.fa-trash-o i.fa.fa-trash-o
span(translate) Reset Settings span(translate) Reset Settings
p
span.text-muted(translate) Saved to: {{savedTo}}