FEATURE: allow users to select theme on single device

This commit is contained in:
Sam 2017-05-15 12:48:08 -04:00
parent a0c936dadb
commit e1dd543a93
11 changed files with 97 additions and 17 deletions

View File

@ -1,21 +1,30 @@
import PreferencesTabController from "discourse/mixins/preferences-tab-controller";
import { default as computed, observes } from "ember-addons/ember-computed-decorators";
import { listThemes, previewTheme } from 'discourse/lib/theme-selector';
import { listThemes, previewTheme, setLocalTheme } from 'discourse/lib/theme-selector';
import { popupAjaxError } from 'discourse/lib/ajax-error';
export default Ember.Controller.extend(PreferencesTabController, {
saveAttrNames: [
'locale',
'external_links_in_new_tab',
'dynamic_favicon',
'enable_quoting',
'disable_jump_reply',
'automatically_unpin_topics',
'theme_key'
],
@computed("makeThemeDefault")
saveAttrNames(makeDefault) {
let attrs = [
'locale',
'external_links_in_new_tab',
'dynamic_favicon',
'enable_quoting',
'disable_jump_reply',
'automatically_unpin_topics'
];
if (makeDefault) {
attrs.push('theme_key');
}
return attrs;
},
preferencesController: Ember.inject.controller('preferences'),
makeThemeDefault: true,
@computed()
availableLocales() {
@ -40,8 +49,15 @@ export default Ember.Controller.extend(PreferencesTabController, {
actions: {
save() {
this.set('saved', false);
const makeThemeDefault = this.get("makeThemeDefault");
return this.get('model').save(this.get('saveAttrNames')).then(() => {
this.set('saved', true);
if (!makeThemeDefault) {
setLocalTheme(this.get('model.user_option.theme_key'), this.get('model.user_option.theme_key_seq'));
}
}).catch(popupAjaxError);
}
}

View File

@ -13,6 +13,14 @@ export function currentThemeKey() {
return themeKey;
}
export function setLocalTheme(key, themeSeq) {
if (key) {
$.cookie('theme_key', `${key},${themeSeq}`, {path: '/', expires: 9999});
} else {
$.cookie('theme_key', null, {path: '/', expires: 1});
}
}
export function refreshCSS(node, hash, newHref, options) {
let $orig = $(node);

View File

@ -4,6 +4,9 @@
<div class="controls">
{{combo-box content=userSelectableThemes value=model.user_option.theme_key}}
</div>
<div class="controls">
{{preference-checkbox labelKey="user.theme_default_on_all_devices" checked=makeThemeDefault}}
</div>
</div>
{{/if}}

View File

@ -267,13 +267,19 @@ class ApplicationController < ActionController::Base
resolve_safe_mode
return if request.env[NO_CUSTOM]
theme_key = flash[:preview_theme_key] || current_user&.user_option&.theme_key
theme_key = flash[:preview_theme_key]
# TODO 2018: delete this, old cookie cleanup code
if cookies[:theme_key]
cookies.delete(:theme_key)
user_option = current_user&.user_option
unless theme_key
key, seq = cookies[:theme_key]&.split(",")
if key && seq && seq.to_i == user_option&.theme_key_seq
theme_key = key
end
end
theme_key ||= user_option&.theme_key
if theme_key && !guardian.allow_theme?(theme_key)
theme_key = nil
end

View File

@ -158,6 +158,7 @@ end
# include_tl0_in_digests :boolean default(FALSE)
# notification_level_when_replying :integer
# theme_key :string
# theme_key_seq :integer default(0), not null
#
# Indexes
#

View File

@ -19,7 +19,8 @@ class UserOptionSerializer < ApplicationSerializer
:email_in_reply_to,
:like_notification_frequency,
:include_tl0_in_digests,
:theme_key
:theme_key,
:theme_key_seq
def auto_track_topics_after_msecs

View File

@ -76,6 +76,11 @@ class UserUpdater
save_options = false
# special handling for theme_key cause we need to bump a sequence number
if attributes.key?(:theme_key) && user.user_option.theme_key != attributes[:theme_key]
user.user_option.theme_key_seq += 1
end
OPTION_ATTR.each do |attribute|
if attributes.key?(attribute)
save_options = true

View File

@ -581,6 +581,7 @@ en:
first_notification: "Your first notification! Select it to begin."
disable_jump_reply: "Don't jump to my post after I reply"
dynamic_favicon: "Show new / updated topic count on browser icon"
theme_default_on_all_devices: "Make this my default theme on all my devices"
external_links_in_new_tab: "Open all external links in a new tab"
enable_quoting: "Enable quote reply for highlighted text"
change: "change"

View File

@ -0,0 +1,5 @@
class AddThemeKeySeqToUserOptions < ActiveRecord::Migration
def change
add_column :user_options, :theme_key_seq, :integer, null: false, default: 0
end
end

View File

@ -18,8 +18,15 @@ describe TopicsController do
end
describe "themes" do
let :theme do
Theme.create!(user_id: -1, name: 'bob', user_selectable: true)
end
let :theme2 do
Theme.create!(user_id: -1, name: 'bobbob', user_selectable: true)
end
it "selects the theme the user has selected" do
theme = Theme.create!(user_id: -1, name: 'bob', user_selectable: true)
user = log_in
user.user_option.update_columns(theme_key: theme.key)
@ -31,6 +38,26 @@ describe TopicsController do
get :show, id: 666
expect(controller.theme_key).not_to eq(theme.key)
end
it "can be overridden with a cookie" do
user = log_in
user.user_option.update_columns(theme_key: theme.key)
cookies['theme_key'] = "#{theme2.key},#{user.user_option.theme_key_seq}"
get :show, id: 666
expect(controller.theme_key).to eq(theme2.key)
end
it "cookie can fail back to user if out of sync" do
user = log_in
user.user_option.update_columns(theme_key: theme.key)
cookies['theme_key'] = "#{theme2.key},#{user.user_option.theme_key_seq-1}"
get :show, id: 666
expect(controller.theme_key).to eq(theme.key)
end
end
it "doesn't store an incoming link when there's no referer" do

View File

@ -66,6 +66,10 @@ describe UserUpdater do
updater = UserUpdater.new(acting_user, user)
date_of_birth = Time.zone.now
theme = Theme.create!(user_id: -1, name: "test", user_selectable: true)
seq = user.user_option.theme_key_seq
val = updater.update(bio_raw: 'my new bio',
email_always: 'true',
mailing_list_mode: true,
@ -74,7 +78,8 @@ describe UserUpdater do
auto_track_topics_after_msecs: 101,
notification_level_when_replying: 3,
email_in_reply_to: false,
date_of_birth: date_of_birth
date_of_birth: date_of_birth,
theme_key: theme.key
)
expect(val).to be_truthy
@ -88,6 +93,8 @@ describe UserUpdater do
expect(user.user_option.auto_track_topics_after_msecs).to eq 101
expect(user.user_option.notification_level_when_replying).to eq 3
expect(user.user_option.email_in_reply_to).to eq false
expect(user.user_option.theme_key).to eq theme.key
expect(user.user_option.theme_key_seq).to eq(seq+1)
expect(user.date_of_birth).to eq(date_of_birth.to_date)
end