diff --git a/frontend_tests/node_tests/dispatch.js b/frontend_tests/node_tests/dispatch.js
index 639c988f27..dacc3cee16 100644
--- a/frontend_tests/node_tests/dispatch.js
+++ b/frontend_tests/node_tests/dispatch.js
@@ -692,20 +692,30 @@ with_overrides(function (override) {
$("body").fadeIn = (secs) => { assert_same(secs, 300); };
global.with_stub(function (stub) {
- event = event_fixtures.update_display_settings__night_mode;
- page_params.night_mode = false;
+ event = event_fixtures.update_display_settings__color_scheme_dark;
+ page_params.color_scheme = 1;
override('night_mode.enable', stub.f); // automatically checks if called
override('realm_logo.rerender', noop);
dispatch(event);
- assert_same(page_params.night_mode, true);
+ assert(page_params.color_scheme, 2);
});
global.with_stub(function (stub) {
- event = event_fixtures.update_display_settings__night_mode_false;
- page_params.night_mode = true;
+ event = event_fixtures.update_display_settings__color_scheme_light;
+ page_params.color_scheme = 1;
override('night_mode.disable', stub.f); // automatically checks if called
+ override('realm_logo.rerender', noop);
dispatch(event);
- assert(!page_params.night_mode);
+ assert(page_params.color_scheme, 3);
+ });
+
+ global.with_stub(function (stub) {
+ event = event_fixtures.update_display_settings__color_scheme_automatic;
+ page_params.color_scheme = 2;
+ override('night_mode.default_preference_checker', stub.f); // automatically checks if called
+ override('realm_logo.rerender', noop);
+ dispatch(event);
+ assert(page_params.color_scheme, 1);
});
global.with_stub(function (stub) {
diff --git a/frontend_tests/node_tests/lib/events.js b/frontend_tests/node_tests/lib/events.js
index 58cba6964b..78c761ad1e 100644
--- a/frontend_tests/node_tests/lib/events.js
+++ b/frontend_tests/node_tests/lib/events.js
@@ -478,16 +478,22 @@ exports.fixtures = {
setting: true,
},
- update_display_settings__night_mode: {
+ update_display_settings__color_scheme_automatic: {
type: 'update_display_settings',
- setting_name: 'night_mode',
- setting: true,
+ setting_name: 'color_scheme',
+ setting: 1,
},
- update_display_settings__night_mode_false: {
+ update_display_settings__color_scheme_dark: {
type: 'update_display_settings',
- setting_name: 'night_mode',
- setting: false,
+ setting_name: 'color_scheme',
+ setting: 2,
+ },
+
+ update_display_settings__color_scheme_light: {
+ type: 'update_display_settings',
+ setting_name: 'color_scheme',
+ setting: 3,
},
update_display_settings__starred_message_counts: {
diff --git a/static/js/night_mode.js b/static/js/night_mode.js
index 2dec1fd6ba..3b32690ec1 100644
--- a/static/js/night_mode.js
+++ b/static/js/night_mode.js
@@ -1,9 +1,13 @@
exports.enable = function () {
- $("body").addClass("night-mode");
+ $("body").removeClass("color-scheme-automatic").addClass("night-mode");
};
exports.disable = function () {
- $("body").removeClass("night-mode");
+ $("body").removeClass("color-scheme-automatic").removeClass("night-mode");
+};
+
+exports.default_preference_checker = function () {
+ $("body").removeClass("night-mode").addClass("color-scheme-automatic");
};
window.night_mode = exports;
diff --git a/static/js/realm_logo.js b/static/js/realm_logo.js
index f067ba15b7..479573d9cf 100644
--- a/static/js/realm_logo.js
+++ b/static/js/realm_logo.js
@@ -1,3 +1,5 @@
+const settings_config = require("./settings_config");
+
exports.build_realm_logo_widget = function (upload_function, is_night) {
let logo_section_id = '#realm-day-logo-upload-widget';
let logo_source = page_params.realm_logo_source;
@@ -73,7 +75,11 @@ exports.rerender = function () {
$("#realm-night-logo-upload-widget .image-block").attr("src", page_params.realm_night_logo_url);
}
- if (page_params.night_mode && page_params.realm_night_logo_source !== 'D') {
+ if (page_params.color_scheme === settings_config.color_scheme_values.night.code &&
+ page_params.realm_night_logo_source !== 'D' ||
+ page_params.color_scheme === settings_config.color_scheme_values.automatic.code &&
+ page_params.realm_night_logo_source !== 'D' &&
+ (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
$("#realm-logo").attr("src", page_params.realm_night_logo_url);
} else {
$("#realm-logo").attr("src", page_params.realm_logo_url);
diff --git a/static/js/server_events_dispatch.js b/static/js/server_events_dispatch.js
index 6272f5e6d9..164e9cb149 100644
--- a/static/js/server_events_dispatch.js
+++ b/static/js/server_events_dispatch.js
@@ -1,3 +1,5 @@
+const settings_config = require("./settings_config");
+
exports.dispatch_normal_event = function dispatch_normal_event(event) {
const noop = function () {};
switch (event.type) {
@@ -395,13 +397,13 @@ exports.dispatch_normal_event = function dispatch_normal_event(event) {
case 'update_display_settings': {
const user_display_settings = [
+ 'color_scheme',
'default_language',
'demote_inactive_streams',
'dense_mode',
'emojiset',
'fluid_layout_width',
'high_contrast_mode',
- 'night_mode',
'left_side_userlist',
'timezone',
'twenty_four_hour_time',
@@ -433,15 +435,18 @@ exports.dispatch_normal_event = function dispatch_normal_event(event) {
$("body").toggleClass("less_dense_mode");
$("body").toggleClass("more_dense_mode");
}
- if (event.setting_name === 'night_mode') {
+ if (event.setting_name === 'color_scheme') {
$("body").fadeOut(300);
setTimeout(function () {
- if (event.setting === true) {
+ if (event.setting === settings_config.color_scheme_values.night.code) {
night_mode.enable();
realm_logo.rerender();
- } else {
+ } else if (event.setting === settings_config.color_scheme_values.day.code) {
night_mode.disable();
realm_logo.rerender();
+ } else {
+ night_mode.default_preference_checker();
+ realm_logo.rerender();
}
$("body").fadeIn(300);
}, 300);
diff --git a/static/js/settings.js b/static/js/settings.js
index fbbf5c9b0e..883f45ea04 100644
--- a/static/js/settings.js
+++ b/static/js/settings.js
@@ -37,7 +37,6 @@ function setup_settings_label() {
fluid_layout_width: i18n.t("Use full width on wide screens"),
high_contrast_mode: i18n.t("High contrast mode"),
left_side_userlist: i18n.t("Show user list on left sidebar in narrow windows"),
- night_mode: i18n.t("Night mode"),
starred_message_counts: i18n.t("Show counts for starred messages"),
twenty_four_hour_time: i18n.t("Time format"),
translate_emoticons: i18n.t("Convert emoticons before sending (:)
becomes 😃)"),
@@ -58,6 +57,7 @@ exports.build_page = function () {
can_create_new_bots: settings_bots.can_create_new_bots(),
settings_label: exports.settings_label,
demote_inactive_streams_values: settings_config.demote_inactive_streams_values,
+ color_scheme_values: settings_config.color_scheme_values,
twenty_four_hour_time_values: settings_config.twenty_four_hour_time_values,
general_settings: settings_config.all_notifications().general_settings,
notification_settings: settings_config.all_notifications().settings,
diff --git a/static/js/settings_config.js b/static/js/settings_config.js
index 25a4854f97..3ecc1e99ad 100644
--- a/static/js/settings_config.js
+++ b/static/js/settings_config.js
@@ -27,6 +27,21 @@ exports.demote_inactive_streams_values = {
},
};
+exports.color_scheme_values = {
+ automatic: {
+ code: 1,
+ description: i18n.t("Automatic"),
+ },
+ night: {
+ code: 2,
+ description: i18n.t("Night mode"),
+ },
+ day: {
+ code: 3,
+ description: i18n.t("Day mode"),
+ },
+};
+
exports.twenty_four_hour_time_values = {
twenty_four_hour_clock: {
value: true,
@@ -42,7 +57,6 @@ exports.get_all_display_settings = () => ({
settings: {
user_display_settings: [
"dense_mode",
- "night_mode",
"high_contrast_mode",
"left_side_userlist",
"starred_message_counts",
diff --git a/static/js/settings_display.js b/static/js/settings_display.js
index 28667d5f06..1bb5d6c759 100644
--- a/static/js/settings_display.js
+++ b/static/js/settings_display.js
@@ -29,6 +29,8 @@ exports.set_up = function () {
$("#demote_inactive_streams").val(page_params.demote_inactive_streams);
+ $("#color_scheme").val(page_params.color_scheme);
+
$("#twenty_four_hour_time").val(JSON.stringify(page_params.twenty_four_hour_time));
$(".emojiset_choice[value=" + page_params.emojiset + "]").prop("checked", true);
@@ -82,6 +84,11 @@ exports.set_up = function () {
change_display_setting(data, '#display-settings-status');
});
+ $('#color_scheme').change(function () {
+ const data = {color_scheme: this.value};
+ change_display_setting(data, '#display-settings-status');
+ });
+
$('body').on('click', '.reload_link', function () {
window.location.reload();
});
@@ -146,8 +153,8 @@ exports.update_page = function () {
$("#left_side_userlist").prop('checked', page_params.left_side_userlist);
$("#default_language_name").text(page_params.default_language_name);
$("#translate_emoticons").prop('checked', page_params.translate_emoticons);
- $("#night_mode").prop('checked', page_params.night_mode);
$("#twenty_four_hour_time").val(JSON.stringify(page_params.twenty_four_hour_time));
+ $("#color_scheme").val(JSON.stringify(page_params.color_scheme));
// TODO: Set emojiset selector here.
// Longer term, we'll want to automate this function
diff --git a/static/styles/night_mode.scss b/static/styles/night_mode.scss
index 90a2440258..885d0271dd 100644
--- a/static/styles/night_mode.scss
+++ b/static/styles/night_mode.scss
@@ -786,3 +786,9 @@ on a dark background, and don't change the dark labels dark either. */
background-color: hsla(0, 0%, 0%, 0.2);
}
}
+
+@media (prefers-color-scheme: dark) {
+ .color-scheme-automatic {
+ @extend body.night-mode;
+ }
+}
diff --git a/static/templates/settings/display_settings.hbs b/static/templates/settings/display_settings.hbs
index f9e9478943..2cca09ebef 100644
--- a/static/templates/settings/display_settings.hbs
+++ b/static/templates/settings/display_settings.hbs
@@ -21,6 +21,14 @@
{{t "Display settings" }}
+
+
+
+
+
{{#each display_settings.settings.user_display_settings}}
{{> settings_checkbox
setting_name=this
diff --git a/templates/zerver/api/changelog.md b/templates/zerver/api/changelog.md
index 84843f0637..b99d94f825 100644
--- a/templates/zerver/api/changelog.md
+++ b/templates/zerver/api/changelog.md
@@ -10,6 +10,11 @@ below features are supported.
## Changes in Zulip 2.2
+**Feature level 21**
+
+* `PATCH /settings/display`: Replaced the `night_mode` boolean with
+ `color_scheme` as part of supporting automatic night theme detection.
+
**Feature level 20**
* Added support for inviting users as organization owners to the
diff --git a/templates/zerver/base.html b/templates/zerver/base.html
index 6958ff7c2c..d043093720 100644
--- a/templates/zerver/base.html
+++ b/templates/zerver/base.html
@@ -29,7 +29,7 @@
{% endblock %}
-
+
{% block content %}
{% endblock %}
diff --git a/templates/zerver/help/night-mode.md b/templates/zerver/help/night-mode.md
index f6de1bff80..7001568929 100644
--- a/templates/zerver/help/night-mode.md
+++ b/templates/zerver/help/night-mode.md
@@ -1,15 +1,21 @@
# Night mode
-By default, Zulip has a white background. Zulip also provides a
-"night mode", which is great for working in a dark space.
+Zulip provides both a light theme and a night theme, which is great
+for working in a dark space.
-### Enable night mode
+## Manage color theme
{start_tabs}
{settings_tab|display-settings}
-2. Under **Display settings**, select **Night mode**.
+2. Under **Display settings**, configure **Color scheme**.
{end_tabs}
-.
+
+The default is **Automatic**, which detects which theme to use based
+on the color scheme used by your operating system.
+
+You can also specifc **Night mode** or **Day mode** if you'd like
+Zulip to use the same color scheme regardless of your operating system
+configuration.
diff --git a/version.py b/version.py
index cab5abf5d8..a6b6dd7e51 100644
--- a/version.py
+++ b/version.py
@@ -29,7 +29,7 @@ DESKTOP_WARNING_VERSION = "5.2.0"
#
# Changes should be accompanied by documentation explaining what the
# new level means in templates/zerver/api/changelog.md.
-API_FEATURE_LEVEL = 20
+API_FEATURE_LEVEL = 21
# Bump the minor PROVISION_VERSION to indicate that folks should provision
# only when going from an old version of the code to a newer version. Bump
diff --git a/zerver/lib/zcommand.py b/zerver/lib/zcommand.py
index 16beb63894..14ed4b9179 100644
--- a/zerver/lib/zcommand.py
+++ b/zerver/lib/zcommand.py
@@ -9,7 +9,7 @@ from zerver.models import UserProfile
def process_zcommands(content: str, user_profile: UserProfile) -> Dict[str, Any]:
def change_mode_setting(command: str, switch_command: str,
- setting: str, setting_value: bool) -> str:
+ setting: str, setting_value: int) -> str:
msg = 'Changed to {command} mode! To revert ' \
'{command} mode, type `/{switch_command}`.'.format(
command=command,
@@ -27,19 +27,19 @@ def process_zcommands(content: str, user_profile: UserProfile) -> Dict[str, Any]
if command == 'ping':
return dict()
elif command == 'night':
- if user_profile.night_mode:
+ if user_profile.color_scheme == UserProfile.COLOR_SCHEME_NIGHT:
return dict(msg='You are still in night mode.')
return dict(msg=change_mode_setting(command=command,
switch_command='day',
- setting='night_mode',
- setting_value=True))
+ setting='color_scheme',
+ setting_value=UserProfile.COLOR_SCHEME_NIGHT))
elif command == 'day':
- if not user_profile.night_mode:
+ if user_profile.color_scheme == UserProfile.COLOR_SCHEME_LIGHT:
return dict(msg='You are still in day mode.')
return dict(msg=change_mode_setting(command=command,
switch_command='night',
- setting='night_mode',
- setting_value=False))
+ setting='color_scheme',
+ setting_value=UserProfile.COLOR_SCHEME_LIGHT))
elif command == 'fluid-width':
if user_profile.fluid_layout_width:
return dict(msg='You are still in fluid width mode.')
diff --git a/zerver/migrations/0290_remove_night_mode_add_color_scheme.py b/zerver/migrations/0290_remove_night_mode_add_color_scheme.py
new file mode 100644
index 0000000000..644cd02485
--- /dev/null
+++ b/zerver/migrations/0290_remove_night_mode_add_color_scheme.py
@@ -0,0 +1,35 @@
+# Generated by Django 2.2.13 on 2020-06-20 15:22
+
+from django.db import migrations, models
+from django.db.backends.postgresql.schema import DatabaseSchemaEditor
+from django.db.migrations.state import StateApps
+
+COLOR_SCHEME_AUTOMATIC = 1
+COLOR_SCHEME_NIGHT = 2
+
+# Set color_scheme to night mode, if night_mode is True.
+def set_color_scheme_to_night_mode(apps: StateApps, schema_editor: DatabaseSchemaEditor) -> None:
+ UserProfile = apps.get_model("zerver", "UserProfile")
+ UserProfile.objects.filter(night_mode=True).update(color_scheme=COLOR_SCHEME_NIGHT)
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('zerver', '0289_tighten_attachment_size'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='userprofile',
+ name='color_scheme',
+ field=models.PositiveSmallIntegerField(default=COLOR_SCHEME_AUTOMATIC),
+ ),
+ migrations.RunPython(
+ set_color_scheme_to_night_mode,
+ reverse_code=migrations.RunPython.noop,
+ elidable=True),
+ migrations.RemoveField(
+ model_name='userprofile',
+ name='night_mode',
+ ),
+ ]
diff --git a/zerver/models.py b/zerver/models.py
index ba1682f7b7..2898184b47 100644
--- a/zerver/models.py
+++ b/zerver/models.py
@@ -999,10 +999,18 @@ class UserProfile(AbstractBaseUser, PermissionsMixin):
dense_mode: bool = models.BooleanField(default=True)
fluid_layout_width: bool = models.BooleanField(default=False)
high_contrast_mode: bool = models.BooleanField(default=False)
- night_mode: bool = models.BooleanField(default=False)
translate_emoticons: bool = models.BooleanField(default=False)
twenty_four_hour_time: bool = models.BooleanField(default=False)
starred_message_counts: bool = models.BooleanField(default=False)
+ COLOR_SCHEME_AUTOMATIC = 1
+ COLOR_SCHEME_NIGHT = 2
+ COLOR_SCHEME_LIGHT = 3
+ COLOR_SCHEME_CHOICES = [
+ COLOR_SCHEME_AUTOMATIC,
+ COLOR_SCHEME_NIGHT,
+ COLOR_SCHEME_LIGHT
+ ]
+ color_scheme = models.PositiveSmallIntegerField(default=COLOR_SCHEME_AUTOMATIC)
# UI setting controlling Zulip's behavior of demoting in the sort
# order and graying out streams with no recent traffic. The
@@ -1069,6 +1077,7 @@ class UserProfile(AbstractBaseUser, PermissionsMixin):
# Define the types of the various automatically managed properties
property_types = dict(
+ color_scheme=int,
default_language=str,
demote_inactive_streams=int,
dense_mode=bool,
@@ -1076,7 +1085,6 @@ class UserProfile(AbstractBaseUser, PermissionsMixin):
fluid_layout_width=bool,
high_contrast_mode=bool,
left_side_userlist=bool,
- night_mode=bool,
starred_message_counts=bool,
timezone=str,
translate_emoticons=bool,
diff --git a/zerver/tests/test_events.py b/zerver/tests/test_events.py
index 6242765a88..d9a2756a22 100644
--- a/zerver/tests/test_events.py
+++ b/zerver/tests/test_events.py
@@ -1852,6 +1852,7 @@ class EventsRegisterTest(ZulipTestCase):
default_language = ['es', 'de', 'en'],
timezone = ['US/Mountain', 'US/Samoa', 'Pacific/Galapogos', ''],
demote_inactive_streams = [2, 3, 1],
+ color_scheme = [2, 3, 1]
)
property_type = UserProfile.property_types[setting_name]
diff --git a/zerver/tests/test_home.py b/zerver/tests/test_home.py
index cd9b0b3985..ad8b148a63 100644
--- a/zerver/tests/test_home.py
+++ b/zerver/tests/test_home.py
@@ -61,6 +61,7 @@ class HomeTest(ZulipTestCase):
"bot_types",
"can_create_streams",
"can_subscribe_other_users",
+ "color_scheme",
"cross_realm_bots",
"custom_profile_field_types",
"custom_profile_fields",
@@ -117,7 +118,6 @@ class HomeTest(ZulipTestCase):
"narrow_stream",
"needs_tutorial",
"never_subscribed",
- "night_mode",
"notification_sound",
"password_min_guesses",
"password_min_length",
@@ -761,34 +761,34 @@ class HomeTest(ZulipTestCase):
def test_compute_navbar_logo_url(self) -> None:
user_profile = self.example_user("hamlet")
- page_params = {"night_mode": True}
+ page_params = {"color_scheme": user_profile.COLOR_SCHEME_NIGHT}
add_realm_logo_fields(page_params, user_profile.realm)
self.assertEqual(compute_navbar_logo_url(page_params),
"/static/images/logo/zulip-org-logo.png?version=0")
- page_params = {"night_mode": False}
+ page_params = {"color_scheme": user_profile.COLOR_SCHEME_LIGHT}
add_realm_logo_fields(page_params, user_profile.realm)
self.assertEqual(compute_navbar_logo_url(page_params),
"/static/images/logo/zulip-org-logo.png?version=0")
do_change_logo_source(user_profile.realm, Realm.LOGO_UPLOADED, night=False)
- page_params = {"night_mode": True}
+ page_params = {"color_scheme": user_profile.COLOR_SCHEME_NIGHT}
add_realm_logo_fields(page_params, user_profile.realm)
self.assertEqual(compute_navbar_logo_url(page_params),
f"/user_avatars/{user_profile.realm_id}/realm/logo.png?version=2")
- page_params = {"night_mode": False}
+ page_params = {"color_scheme": user_profile.COLOR_SCHEME_LIGHT}
add_realm_logo_fields(page_params, user_profile.realm)
self.assertEqual(compute_navbar_logo_url(page_params),
f"/user_avatars/{user_profile.realm_id}/realm/logo.png?version=2")
do_change_logo_source(user_profile.realm, Realm.LOGO_UPLOADED, night=True)
- page_params = {"night_mode": True}
+ page_params = {"color_scheme": user_profile.COLOR_SCHEME_NIGHT}
add_realm_logo_fields(page_params, user_profile.realm)
self.assertEqual(compute_navbar_logo_url(page_params),
f"/user_avatars/{user_profile.realm_id}/realm/night_logo.png?version=2")
- page_params = {"night_mode": False}
+ page_params = {"color_scheme": user_profile.COLOR_SCHEME_LIGHT}
add_realm_logo_fields(page_params, user_profile.realm)
self.assertEqual(compute_navbar_logo_url(page_params),
f"/user_avatars/{user_profile.realm_id}/realm/logo.png?version=2")
@@ -796,12 +796,12 @@ class HomeTest(ZulipTestCase):
# This configuration isn't super supported in the UI and is a
# weird choice, but we have a test for it anyway.
do_change_logo_source(user_profile.realm, Realm.LOGO_DEFAULT, night=False)
- page_params = {"night_mode": True}
+ page_params = {"color_scheme": user_profile.COLOR_SCHEME_NIGHT}
add_realm_logo_fields(page_params, user_profile.realm)
self.assertEqual(compute_navbar_logo_url(page_params),
f"/user_avatars/{user_profile.realm_id}/realm/night_logo.png?version=2")
- page_params = {"night_mode": False}
+ page_params = {"color_scheme": user_profile.COLOR_SCHEME_LIGHT}
add_realm_logo_fields(page_params, user_profile.realm)
self.assertEqual(compute_navbar_logo_url(page_params),
"/static/images/logo/zulip-org-logo.png?version=0")
diff --git a/zerver/tests/test_middleware.py b/zerver/tests/test_middleware.py
index 6506b73f04..694d064d71 100644
--- a/zerver/tests/test_middleware.py
+++ b/zerver/tests/test_middleware.py
@@ -83,9 +83,8 @@ class OpenGraphTest(ZulipTestCase):
self.check_title_and_description(
'/help/night-mode',
"Night mode (Zulip Help Center)",
- ['By default, Zulip has a white background. ',
- 'Zulip also provides a "night mode", which is great for working in a dark space.'],
- [],
+ ['Zulip provides both a white background and a "night mode", which is great for working in a dark space.'],
+ []
)
def test_settings_tab(self) -> None:
diff --git a/zerver/tests/test_settings.py b/zerver/tests/test_settings.py
index 246ae6f687..9626c5104f 100644
--- a/zerver/tests/test_settings.py
+++ b/zerver/tests/test_settings.py
@@ -322,6 +322,7 @@ class ChangeSettingsTest(ZulipTestCase):
emojiset = 'google',
timezone = 'US/Mountain',
demote_inactive_streams = 2,
+ color_scheme = 2,
)
self.login('hamlet')
diff --git a/zerver/tests/test_users.py b/zerver/tests/test_users.py
index f2d2f6ec8b..58df104385 100644
--- a/zerver/tests/test_users.py
+++ b/zerver/tests/test_users.py
@@ -1020,11 +1020,12 @@ class UserProfileTest(ZulipTestCase):
iago = self.example_user("iago")
cordelia = self.example_user("cordelia")
hamlet = self.example_user("hamlet")
+ hamlet.color_scheme = UserProfile.COLOR_SCHEME_LIGHT
cordelia.default_language = "de"
cordelia.emojiset = "twitter"
cordelia.timezone = "America/Phoenix"
- cordelia.night_mode = True
+ cordelia.color_scheme = UserProfile.COLOR_SCHEME_NIGHT
cordelia.enable_offline_email_notifications = False
cordelia.enable_stream_push_notifications = True
cordelia.enter_sends = False
@@ -1055,9 +1056,9 @@ class UserProfileTest(ZulipTestCase):
self.assertEqual(cordelia.timezone, "America/Phoenix")
self.assertEqual(hamlet.timezone, "")
- self.assertEqual(iago.night_mode, True)
- self.assertEqual(cordelia.night_mode, True)
- self.assertEqual(hamlet.night_mode, False)
+ self.assertEqual(iago.color_scheme, UserProfile.COLOR_SCHEME_NIGHT)
+ self.assertEqual(cordelia.color_scheme, UserProfile.COLOR_SCHEME_NIGHT)
+ self.assertEqual(hamlet.color_scheme, UserProfile.COLOR_SCHEME_LIGHT)
self.assertEqual(iago.enable_offline_email_notifications, False)
self.assertEqual(cordelia.enable_offline_email_notifications, False)
diff --git a/zerver/tests/test_zcommand.py b/zerver/tests/test_zcommand.py
index 08c1ca7d16..abf2afc134 100644
--- a/zerver/tests/test_zcommand.py
+++ b/zerver/tests/test_zcommand.py
@@ -1,4 +1,5 @@
from zerver.lib.test_classes import ZulipTestCase
+from zerver.models import UserProfile
class ZcommandTest(ZulipTestCase):
@@ -24,7 +25,7 @@ class ZcommandTest(ZulipTestCase):
def test_night_zcommand(self) -> None:
self.login('hamlet')
user = self.example_user('hamlet')
- user.night_mode = False
+ user.color_scheme = UserProfile.COLOR_SCHEME_LIGHT
user.save()
payload = dict(command="/night")
@@ -39,7 +40,7 @@ class ZcommandTest(ZulipTestCase):
def test_day_zcommand(self) -> None:
self.login('hamlet')
user = self.example_user('hamlet')
- user.night_mode = True
+ user.color_scheme = UserProfile.COLOR_SCHEME_NIGHT
user.save()
payload = dict(command="/day")
diff --git a/zerver/views/home.py b/zerver/views/home.py
index 3976b15073..04d4174a79 100644
--- a/zerver/views/home.py
+++ b/zerver/views/home.py
@@ -129,7 +129,7 @@ def get_bot_types(user_profile: Optional[UserProfile]) -> List[Dict[str, object]
return bot_types
def compute_navbar_logo_url(page_params: Dict[str, Any]) -> str:
- if page_params["night_mode"] and page_params["realm_night_logo_source"] != Realm.LOGO_DEFAULT:
+ if page_params["color_scheme"] == 2 and page_params["realm_night_logo_source"] != Realm.LOGO_DEFAULT:
navbar_logo_url = page_params["realm_night_logo_url"]
else:
navbar_logo_url = page_params["realm_logo_url"]
@@ -315,13 +315,13 @@ def home_real(request: HttpRequest) -> HttpResponse:
csp_nonce = generate_random_token(48)
if user_profile is not None:
- night_mode = user_profile.night_mode
+ color_scheme = user_profile.color_scheme
is_guest = user_profile.is_guest
is_realm_owner = user_profile.is_realm_owner
is_realm_admin = user_profile.is_realm_admin
show_webathena = user_profile.realm.webathena_enabled
else: # nocoverage
- night_mode = False
+ color_scheme = UserProfile.COLOR_SCHEME_AUTOMATIC
is_guest = False
is_realm_admin = False
is_realm_owner = False
@@ -342,7 +342,7 @@ def home_real(request: HttpRequest) -> HttpResponse:
'is_owner': is_realm_owner,
'is_admin': is_realm_admin,
'is_guest': is_guest,
- 'night_mode': night_mode,
+ 'color_scheme': color_scheme,
'navbar_logo_url': navbar_logo_url,
'show_webathena': show_webathena,
'embedded': narrow_stream is not None,
diff --git a/zerver/views/user_settings.py b/zerver/views/user_settings.py
index 8575bf8e82..db10ab4376 100644
--- a/zerver/views/user_settings.py
+++ b/zerver/views/user_settings.py
@@ -165,7 +165,8 @@ def update_display_settings_backend(
starred_message_counts: Optional[bool]=REQ(validator=check_bool, default=None),
fluid_layout_width: Optional[bool]=REQ(validator=check_bool, default=None),
high_contrast_mode: Optional[bool]=REQ(validator=check_bool, default=None),
- night_mode: Optional[bool]=REQ(validator=check_bool, default=None),
+ color_scheme: Optional[int]=REQ(validator=check_int_in(
+ UserProfile.COLOR_SCHEME_CHOICES), default=None),
translate_emoticons: Optional[bool]=REQ(validator=check_bool, default=None),
default_language: Optional[str]=REQ(validator=check_string, default=None),
left_side_userlist: Optional[bool]=REQ(validator=check_bool, default=None),