Skip to content

Commit

Permalink
FEATURE: allow users to select theme on single device
Browse files Browse the repository at this point in the history
  • Loading branch information
SamSaffron committed May 15, 2017
1 parent a0c936d commit e1dd543
Show file tree
Hide file tree
Showing 11 changed files with 97 additions and 17 deletions.
@@ -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() {
Expand All @@ -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);
}
}
Expand Down
8 changes: 8 additions & 0 deletions app/assets/javascripts/discourse/lib/theme-selector.js.es6
Expand Up @@ -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);
Expand Down
Expand Up @@ -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}}

Expand Down
14 changes: 10 additions & 4 deletions app/controllers/application_controller.rb
Expand Up @@ -267,13 +267,19 @@ def handle_theme
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
Expand Down
1 change: 1 addition & 0 deletions app/models/user_option.rb
Expand Up @@ -158,6 +158,7 @@ def treat_as_new_topic_start_date
# include_tl0_in_digests :boolean default(FALSE)
# notification_level_when_replying :integer
# theme_key :string
# theme_key_seq :integer default(0), not null
#
# Indexes
#
Expand Down
3 changes: 2 additions & 1 deletion app/serializers/user_option_serializer.rb
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions app/services/user_updater.rb
Expand Up @@ -76,6 +76,11 @@ def update(attributes = {})

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
Expand Down
1 change: 1 addition & 0 deletions config/locales/client.en.yml
Expand Up @@ -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"
Expand Down
@@ -0,0 +1,5 @@
class AddThemeKeySeqToUserOptions < ActiveRecord::Migration
def change
add_column :user_options, :theme_key_seq, :integer, null: false, default: 0
end
end
29 changes: 28 additions & 1 deletion spec/controllers/application_controller_spec.rb
Expand Up @@ -18,8 +18,15 @@ def set_accept_language(locale)
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)

Expand All @@ -31,6 +38,26 @@ def set_accept_language(locale)
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
Expand Down
9 changes: 8 additions & 1 deletion spec/services/user_updater_spec.rb
Expand Up @@ -66,6 +66,10 @@
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,
Expand All @@ -74,7 +78,8 @@
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

Expand All @@ -88,6 +93,8 @@
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

Expand Down

0 comments on commit e1dd543

Please sign in to comment.