Added a user setting to chose darkmode or not
This commit is contained in:
+1
-1
@@ -37,7 +37,7 @@
|
||||
${tr:Lms.Auth.remember-me}
|
||||
</label>
|
||||
<div class="col-sm-5">
|
||||
${remember-me}
|
||||
<div class="checkbox"><label>${remember-me}</label></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
|
||||
@@ -155,8 +155,10 @@
|
||||
|
||||
|
||||
<!--Settings-->
|
||||
<message id="Lms.Settings.appearance">Appearance</message>
|
||||
<message id="Lms.Settings.audio">Audio</message>
|
||||
<message id="Lms.Settings.change-password">Change password</message>
|
||||
<message id="Lms.Settings.dark-mode">Dark mode</message>
|
||||
<message id="Lms.Settings.demo-cannot-save">Cannot save using a demo account!</message>
|
||||
<message id="Lms.Settings.password-bad">Bad password</message>
|
||||
<message id="Lms.Settings.password-must-fill-old-password">Old password must be filled in</message>
|
||||
|
||||
+17
-3
@@ -4,16 +4,30 @@
|
||||
<!--FORMS message blocks-->
|
||||
|
||||
<message id="Lms.Settings.template">
|
||||
<legend>${tr:Lms.Settings.appearance}</legend>
|
||||
<div class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="${id:dark-mode}">
|
||||
${tr:Lms.Settings.dark-mode}
|
||||
</label>
|
||||
<div class="col-sm-5">
|
||||
<div class="checkbox"><label>${dark-mode}</label></div>
|
||||
</div>
|
||||
<div class="col-sm-5 help-block">
|
||||
${dark-mode-info}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<legend>${tr:Lms.Settings.audio}</legend>
|
||||
<div class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="${id:transcoding-enable}">
|
||||
<label class="col-sm-2 control-label" for="${id:transcoding-enable}">
|
||||
${tr:Lms.Settings.transcoding-enable}
|
||||
</label>
|
||||
<div class="col-sm-5">
|
||||
${transcoding-enable}
|
||||
<div class="checkbox"><label>${transcoding-enable}</label></div>
|
||||
</div>
|
||||
<div class="help-block col-sm-5">
|
||||
<div class="col-sm-5 help-block">
|
||||
${transcoding-enable-info}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
namespace Database {
|
||||
|
||||
#define LMS_DATABASE_VERSION 15
|
||||
#define LMS_DATABASE_VERSION 16
|
||||
|
||||
using Version = std::size_t;
|
||||
|
||||
@@ -169,6 +169,10 @@ CREATE TABLE IF NOT EXISTS "track_bookmark" (
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(*this).modify()->incScanVersion();
|
||||
}
|
||||
else if (version == 15)
|
||||
{
|
||||
_session.execute("ALTER TABLE user ADD ui_theme INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(User::defaultUITheme)) + ")");
|
||||
}
|
||||
else
|
||||
{
|
||||
LMS_LOG(DB, ERROR) << "Database version " << version << " cannot be handled using migration";
|
||||
|
||||
@@ -91,14 +91,13 @@ class User : public Wt::Dbo::Dbo<User>
|
||||
public:
|
||||
using pointer = Wt::Dbo::ptr<User>;
|
||||
|
||||
static const std::size_t MinNameLength = 3;
|
||||
static const std::size_t MaxNameLength = 15;
|
||||
|
||||
// Do not change enum values!
|
||||
enum class Type
|
||||
{
|
||||
REGULAR,
|
||||
ADMIN,
|
||||
DEMO
|
||||
REGULAR = 0,
|
||||
ADMIN = 1,
|
||||
DEMO = 2,
|
||||
};
|
||||
|
||||
struct PasswordHash
|
||||
@@ -107,8 +106,21 @@ class User : public Wt::Dbo::Dbo<User>
|
||||
std::string hash;
|
||||
};
|
||||
|
||||
// list of audio parameters
|
||||
// Do not change enum values!
|
||||
enum class UITheme
|
||||
{
|
||||
Light = 0,
|
||||
Dark = 1,
|
||||
};
|
||||
|
||||
static const std::set<Bitrate> audioTranscodeAllowedBitrates;
|
||||
static inline const std::size_t MinNameLength {3};
|
||||
static inline const std::size_t MaxNameLength {15};
|
||||
static inline const bool defaultAudioTranscodeEnable {true};
|
||||
static inline const AudioFormat defaultAudioTranscodeFormat {AudioFormat::OGG_OPUS};
|
||||
static inline const Bitrate defaultAudioTranscodeBitrate {128000};
|
||||
static inline const UITheme defaultUITheme {UITheme::Dark};
|
||||
|
||||
|
||||
User();
|
||||
User(const std::string& loginName, const PasswordHash& passwordHash);
|
||||
@@ -138,6 +150,7 @@ class User : public Wt::Dbo::Dbo<User>
|
||||
void setCurPlayingTrackPos(std::size_t pos) { _curPlayingTrackPos = pos; }
|
||||
void setRadio(bool val) { _radio = val; }
|
||||
void setRepeatAll(bool val) { _repeatAll = val; }
|
||||
void setUITheme(UITheme uiTheme) { _uiTheme = uiTheme; }
|
||||
void clearAuthTokens();
|
||||
|
||||
// read
|
||||
@@ -150,6 +163,7 @@ class User : public Wt::Dbo::Dbo<User>
|
||||
std::size_t getCurPlayingTrackPos() const { return _curPlayingTrackPos; }
|
||||
bool isRepeatAllSet() const { return _repeatAll; }
|
||||
bool isRadioSet() const { return _radio; }
|
||||
UITheme getUITheme() const { return _uiTheme; }
|
||||
|
||||
Wt::Dbo::ptr<TrackList> getPlayedTrackList(Session& session) const;
|
||||
Wt::Dbo::ptr<TrackList> getQueuedTrackList(Session& session) const;
|
||||
@@ -184,6 +198,7 @@ class User : public Wt::Dbo::Dbo<User>
|
||||
Wt::Dbo::field(a, _audioTranscodeEnable, "audio_transcode_enable");
|
||||
Wt::Dbo::field(a, _audioTranscodeBitrate, "audio_transcode_bitrate");
|
||||
Wt::Dbo::field(a, _audioTranscodeFormat, "audio_transcode_format");
|
||||
Wt::Dbo::field(a, _uiTheme, "ui_theme");
|
||||
// User's dynamic data
|
||||
Wt::Dbo::field(a, _curPlayingTrackPos, "cur_playing_track_pos");
|
||||
Wt::Dbo::field(a, _repeatAll, "repeat_all");
|
||||
@@ -197,14 +212,11 @@ class User : public Wt::Dbo::Dbo<User>
|
||||
|
||||
private:
|
||||
|
||||
static const bool defaultAudioTranscodeEnable {true};
|
||||
static const AudioFormat defaultAudioTranscodeFormat {AudioFormat::OGG_OPUS};
|
||||
static const Bitrate defaultAudioTranscodeBitrate {128000};
|
||||
|
||||
std::string _loginName;
|
||||
std::string _passwordSalt;
|
||||
std::string _passwordHash;
|
||||
Wt::WDateTime _lastLogin;
|
||||
UITheme _uiTheme {defaultUITheme};
|
||||
|
||||
// Admin defined settings
|
||||
int _maxAudioTranscodeBitrate;
|
||||
|
||||
@@ -58,6 +58,40 @@
|
||||
|
||||
namespace UserInterface {
|
||||
|
||||
class LmsBooststrapTheme : public Wt::WBootstrapTheme
|
||||
{
|
||||
public:
|
||||
LmsBooststrapTheme(Database::User::UITheme theme) : _theme {theme} {}
|
||||
|
||||
private:
|
||||
std::vector<Wt::WLinkedCssStyleSheet> styleSheets() const override
|
||||
{
|
||||
switch (_theme)
|
||||
{
|
||||
case Database::User::UITheme::Dark:
|
||||
return
|
||||
{
|
||||
Wt::WLinkedCssStyleSheet {"css/bootstrap-darkly.min.css"},
|
||||
Wt::WLinkedCssStyleSheet {"resources/themes/bootstrap/3/wt.css"},
|
||||
Wt::WLinkedCssStyleSheet {"css/lms.css"},
|
||||
Wt::WLinkedCssStyleSheet {"css/lms-darkly.css"},
|
||||
};
|
||||
|
||||
case Database::User::UITheme::Light:
|
||||
return
|
||||
{
|
||||
Wt::WLinkedCssStyleSheet {"css/bootstrap-flatly.min.css"},
|
||||
Wt::WLinkedCssStyleSheet {"resources/themes/bootstrap/3/wt.css"},
|
||||
Wt::WLinkedCssStyleSheet {"css/lms.css"},
|
||||
Wt::WLinkedCssStyleSheet {"css/lms-flatly.css"},
|
||||
};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
Database::User::UITheme _theme;
|
||||
};
|
||||
|
||||
std::unique_ptr<Wt::WApplication>
|
||||
LmsApplication::create(const Wt::WEnvironment& env, Database::Db& db, LmsApplicationGroupContainer& appGroups)
|
||||
{
|
||||
@@ -116,31 +150,8 @@ LmsApplication::LmsApplication(const Wt::WEnvironment& env,
|
||||
_dbSession {db},
|
||||
_appGroups {appGroups}
|
||||
{
|
||||
|
||||
class MyTheme : public Wt::WBootstrapTheme
|
||||
{
|
||||
private:
|
||||
std::vector<Wt::WLinkedCssStyleSheet> styleSheets() const override
|
||||
{
|
||||
return
|
||||
{
|
||||
// Wt::WLinkedCssStyleSheet {Wt::WLink {"css/bootstrap-flatly.min.css"}},
|
||||
Wt::WLinkedCssStyleSheet {Wt::WLink {"css/bootstrap-darkly.min.css"}},
|
||||
Wt::WLinkedCssStyleSheet {Wt::WLink {"resources/themes/bootstrap/3/wt.css"}},
|
||||
// Wt::WLinkedCssStyleSheet {Wt::WLink {"css/lms-flatly.css"}},
|
||||
Wt::WLinkedCssStyleSheet {Wt::WLink {"css/lms-darkly.css"}},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
auto bootstrapTheme = std::make_unique<MyTheme>();
|
||||
bootstrapTheme->setVersion(Wt::BootstrapVersion::v3);
|
||||
bootstrapTheme->setResponsive(true);
|
||||
setTheme(std::move(bootstrapTheme));
|
||||
|
||||
addMetaHeader(Wt::MetaHeaderType::Meta, "viewport", "width=device-width, user-scalable=no");
|
||||
|
||||
useStyleSheet("css/lms.css");
|
||||
useStyleSheet("resources/font-awesome/css/font-awesome.min.css");
|
||||
|
||||
// Add a resource bundle
|
||||
@@ -196,6 +207,22 @@ LmsApplication::LmsApplication(const Wt::WEnvironment& env,
|
||||
}
|
||||
|
||||
const auto userId {processAuthToken(env)};
|
||||
|
||||
{
|
||||
Database::User::UITheme theme {Database::User::defaultUITheme};
|
||||
if (userId)
|
||||
{
|
||||
auto transaction {_dbSession.createSharedTransaction()};
|
||||
const auto user {Database::User::getById(_dbSession, *userId)};
|
||||
if (user)
|
||||
theme = user->getUITheme();
|
||||
}
|
||||
auto LmsTheme {std::make_unique<LmsBooststrapTheme>(theme)};
|
||||
LmsTheme->setVersion(Wt::BootstrapVersion::v3);
|
||||
LmsTheme->setResponsive(true);
|
||||
setTheme(std::move(LmsTheme));
|
||||
}
|
||||
|
||||
if (userId)
|
||||
{
|
||||
try
|
||||
|
||||
+19
-15
@@ -44,18 +44,20 @@ class SettingsModel : public Wt::WFormModel
|
||||
{
|
||||
public:
|
||||
// Associate each field with a unique string literal.
|
||||
static const Field TranscodeEnableField;
|
||||
static const Field TranscodeFormatField;
|
||||
static const Field TranscodeBitrateField;
|
||||
static const Field PasswordOldField;
|
||||
static const Field PasswordField;
|
||||
static const Field PasswordConfirmField;
|
||||
static inline const Field DarkModeField {"dark-mode"};
|
||||
static inline const Field TranscodeEnableField {"transcoding-enable"};
|
||||
static inline const Field TranscodeFormatField {"transcoding-bitrate"};
|
||||
static inline const Field TranscodeBitrateField {"transcoding-format"};
|
||||
static inline const Field PasswordOldField {"password-old"};
|
||||
static inline const Field PasswordField {"password"};
|
||||
static inline const Field PasswordConfirmField {"password-confirm"};
|
||||
|
||||
SettingsModel(bool withOldPassword)
|
||||
: _withOldPassword {withOldPassword}
|
||||
{
|
||||
initializeModels();
|
||||
|
||||
addField(DarkModeField);
|
||||
addField(TranscodeEnableField);
|
||||
addField(TranscodeBitrateField);
|
||||
addField(TranscodeFormatField);
|
||||
@@ -77,15 +79,16 @@ class SettingsModel : public Wt::WFormModel
|
||||
|
||||
void saveData()
|
||||
{
|
||||
Database::User::PasswordHash passwordHash;
|
||||
User::PasswordHash passwordHash;
|
||||
|
||||
if (!valueText(PasswordField).empty())
|
||||
passwordHash = ServiceProvider<::Auth::IPasswordService>::get()->hashPassword(valueText(PasswordField).toUTF8());
|
||||
|
||||
auto transaction {LmsApp->getDbSession().createUniqueTransaction()};
|
||||
|
||||
Database::User::pointer user {LmsApp->getUser()};
|
||||
User::pointer user {LmsApp->getUser()};
|
||||
|
||||
user.modify()->setUITheme(Wt::asNumber(value(DarkModeField)) ? User::UITheme::Dark : User::UITheme::Light);
|
||||
user.modify()->setAudioTranscodeEnable(Wt::asNumber(value(TranscodeEnableField)));
|
||||
|
||||
auto transcodeBitrateRow {_transcodeBitrateModel->getRowFromString(valueText(TranscodeBitrateField))};
|
||||
@@ -107,6 +110,8 @@ class SettingsModel : public Wt::WFormModel
|
||||
{
|
||||
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
|
||||
|
||||
setValue(DarkModeField, LmsApp->getUser()->getUITheme() == User::UITheme::Dark);
|
||||
|
||||
setValue(TranscodeEnableField, LmsApp->getUser()->getAudioTranscodeEnable());
|
||||
if (!LmsApp->getUser()->getAudioTranscodeEnable())
|
||||
{
|
||||
@@ -223,13 +228,6 @@ class SettingsModel : public Wt::WFormModel
|
||||
std::shared_ptr<ValueStringModel<AudioFormat>> _transcodeFormatModel;
|
||||
};
|
||||
|
||||
const Wt::WFormModel::Field SettingsModel::TranscodeEnableField = "transcoding-enable";
|
||||
const Wt::WFormModel::Field SettingsModel::TranscodeBitrateField = "transcoding-bitrate";
|
||||
const Wt::WFormModel::Field SettingsModel::TranscodeFormatField = "transcoding-format";
|
||||
const Wt::WFormModel::Field SettingsModel::PasswordOldField = "password-old";
|
||||
const Wt::WFormModel::Field SettingsModel::PasswordField = "password";
|
||||
const Wt::WFormModel::Field SettingsModel::PasswordConfirmField = "password-confirm";
|
||||
|
||||
SettingsView::SettingsView()
|
||||
{
|
||||
wApp->internalPathChanged().connect(std::bind([=]
|
||||
@@ -252,6 +250,12 @@ SettingsView::refreshView()
|
||||
|
||||
auto model {std::make_shared<SettingsModel>(!LmsApp->isUserAuthStrong())};
|
||||
|
||||
// Appearance
|
||||
{
|
||||
auto darkMode {std::make_unique<Wt::WCheckBox>()};
|
||||
t->setFormWidget(SettingsModel::DarkModeField, std::move(darkMode));
|
||||
}
|
||||
|
||||
// Old password
|
||||
if (!LmsApp->isUserAuthStrong())
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user