Skip to content

Commit 7cd424f

Browse files
committed
Add appearance section in settings
1 parent ff96388 commit 7cd424f

File tree

9 files changed

+161
-89
lines changed

9 files changed

+161
-89
lines changed

options/locale/locale_en-US.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,7 @@ form.name_chars_not_allowed = User name '%s' contains invalid characters.
490490
[settings]
491491
profile = Profile
492492
account = Account
493+
appearance = Appearance
493494
password = Password
494495
security = Security
495496
avatar = Avatar
@@ -514,7 +515,9 @@ website = Website
514515
location = Location
515516
update_theme = Update Theme
516517
update_profile = Update Profile
518+
update_language = Update Language
517519
update_language_not_found = Language '%s' is not available.
520+
update_language_success = Language has been updated.
518521
update_profile_success = Your profile has been updated.
519522
change_username = Your username has been changed.
520523
change_username_prompt = Note: username changes also change your account URL.

routers/web/user/setting/account.go

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -257,34 +257,6 @@ func DeleteAccount(ctx *context.Context) {
257257
}
258258
}
259259

260-
// UpdateUIThemePost is used to update users' specific theme
261-
func UpdateUIThemePost(ctx *context.Context) {
262-
form := web.GetForm(ctx).(*forms.UpdateThemeForm)
263-
ctx.Data["Title"] = ctx.Tr("settings")
264-
ctx.Data["PageIsSettingsAccount"] = true
265-
266-
if ctx.HasError() {
267-
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
268-
return
269-
}
270-
271-
if !form.IsThemeExists() {
272-
ctx.Flash.Error(ctx.Tr("settings.theme_update_error"))
273-
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
274-
return
275-
}
276-
277-
if err := ctx.User.UpdateTheme(form.Theme); err != nil {
278-
ctx.Flash.Error(ctx.Tr("settings.theme_update_error"))
279-
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
280-
return
281-
}
282-
283-
log.Trace("Update user theme: %s", ctx.User.Name)
284-
ctx.Flash.Success(ctx.Tr("settings.theme_update_success"))
285-
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
286-
}
287-
288260
func loadAccountData(ctx *context.Context) {
289261
emlist, err := models.GetEmailAddresses(ctx.User.ID)
290262
if err != nil {

routers/web/user/setting/profile.go

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232

3333
const (
3434
tplSettingsProfile base.TplName = "user/settings/profile"
35+
tplSettingsAppearance base.TplName = "user/settings/appearance"
3536
tplSettingsOrganization base.TplName = "user/settings/organization"
3637
tplSettingsRepositories base.TplName = "user/settings/repos"
3738
)
@@ -115,14 +116,6 @@ func ProfilePost(ctx *context.Context) {
115116
ctx.User.KeepEmailPrivate = form.KeepEmailPrivate
116117
ctx.User.Website = form.Website
117118
ctx.User.Location = form.Location
118-
if len(form.Language) != 0 {
119-
if !util.IsStringInSlice(form.Language, setting.Langs) {
120-
ctx.Flash.Error(ctx.Tr("settings.update_language_not_found", form.Language))
121-
ctx.Redirect(setting.AppSubURL + "/user/settings")
122-
return
123-
}
124-
ctx.User.Language = form.Language
125-
}
126119
ctx.User.Description = form.Description
127120
ctx.User.KeepActivityPrivate = form.KeepActivityPrivate
128121
ctx.User.Visibility = form.Visibility
@@ -329,3 +322,68 @@ func Repos(ctx *context.Context) {
329322
ctx.Data["Page"] = pager
330323
ctx.HTML(http.StatusOK, tplSettingsRepositories)
331324
}
325+
326+
// Profile render user's profile page
327+
func Appearance(ctx *context.Context) {
328+
ctx.Data["Title"] = ctx.Tr("settings")
329+
ctx.Data["PageIsSettingsAppearance"] = true
330+
331+
ctx.HTML(http.StatusOK, tplSettingsAppearance)
332+
}
333+
334+
// UpdateUIThemePost is used to update users' specific theme
335+
func UpdateUIThemePost(ctx *context.Context) {
336+
form := web.GetForm(ctx).(*forms.UpdateThemeForm)
337+
ctx.Data["Title"] = ctx.Tr("settings")
338+
ctx.Data["PageIsSettingsAppearance"] = true
339+
340+
if ctx.HasError() {
341+
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
342+
return
343+
}
344+
345+
if !form.IsThemeExists() {
346+
ctx.Flash.Error(ctx.Tr("settings.theme_update_error"))
347+
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
348+
return
349+
}
350+
351+
if err := ctx.User.UpdateTheme(form.Theme); err != nil {
352+
ctx.Flash.Error(ctx.Tr("settings.theme_update_error"))
353+
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
354+
return
355+
}
356+
357+
log.Trace("Update user theme: %s", ctx.User.Name)
358+
ctx.Flash.Success(ctx.Tr("settings.theme_update_success"))
359+
ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
360+
}
361+
362+
// UpdateUserLang update a user's language
363+
func UpdateUserLang(ctx *context.Context) {
364+
form := web.GetForm(ctx).(*forms.UpdateLanguageForm)
365+
ctx.Data["Title"] = ctx.Tr("settings")
366+
ctx.Data["PageIsSettingsAppearance"] = true
367+
368+
if len(form.Language) != 0 {
369+
if !util.IsStringInSlice(form.Language, setting.Langs) {
370+
ctx.Flash.Error(ctx.Tr("settings.update_language_not_found", form.Language))
371+
ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
372+
return
373+
}
374+
ctx.User.Language = form.Language
375+
}
376+
377+
if err := models.UpdateUserSetting(ctx.User); err != nil {
378+
ctx.ServerError("UpdateUserSetting", err)
379+
return
380+
}
381+
382+
// Update the language to the one we just set
383+
middleware.SetLocaleCookie(ctx.Resp, ctx.User.Language, 0)
384+
385+
log.Trace("User settings updated: %s", ctx.User.Name)
386+
ctx.Flash.Success(i18n.Tr(ctx.User.Language, "settings.update_language_success"))
387+
ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
388+
389+
}

routers/web/web.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,10 @@ func RegisterRoutes(m *web.Route) {
317317
m.Post("/email", bindIgnErr(forms.AddEmailForm{}), userSetting.EmailPost)
318318
m.Post("/email/delete", userSetting.DeleteEmail)
319319
m.Post("/delete", userSetting.DeleteAccount)
320+
})
321+
m.Group("/appearance", func() {
322+
m.Get("", userSetting.Appearance)
323+
m.Post("/language", bindIgnErr(forms.UpdateLanguageForm{}), userSetting.UpdateUserLang)
320324
m.Post("/theme", bindIgnErr(forms.UpdateThemeForm{}), userSetting.UpdateUIThemePost)
321325
})
322326
m.Group("/security", func() {

services/forms/user_form.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,6 @@ type UpdateProfileForm struct {
240240
KeepEmailPrivate bool
241241
Website string `binding:"ValidSiteUrl;MaxSize(255)"`
242242
Location string `binding:"MaxSize(50)"`
243-
Language string
244243
Description string `binding:"MaxSize(255)"`
245244
Visibility structs.VisibleType
246245
KeepActivityPrivate bool
@@ -252,6 +251,17 @@ func (f *UpdateProfileForm) Validate(req *http.Request, errs binding.Errors) bin
252251
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
253252
}
254253

254+
// UpdateLanguageForm form for updating profile
255+
type UpdateLanguageForm struct {
256+
Language string
257+
}
258+
259+
// Validate validates the fields
260+
func (f *UpdateLanguageForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
261+
ctx := context.GetContext(req)
262+
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
263+
}
264+
255265
// Avatar types
256266
const (
257267
AvatarLocal string = "local"

templates/user/settings/account.tmpl

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -130,44 +130,6 @@
130130
</form>
131131
</div>
132132

133-
<h4 class="ui top attached header">
134-
{{.i18n.Tr "settings.manage_themes"}}
135-
</h4>
136-
<div class="ui attached segment">
137-
<div class="ui email list">
138-
<div class="item">
139-
{{.i18n.Tr "settings.theme_desc"}}
140-
</div>
141-
142-
<form class="ui form" action="{{.Link}}/theme" method="post">
143-
{{.CsrfTokenHtml}}
144-
<div class="field">
145-
<label for="ui">{{.i18n.Tr "settings.ui"}}</label>
146-
<div class="ui selection dropdown" id="ui">
147-
<input name="theme" type="hidden" value="{{.SignedUser.Theme}}">
148-
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
149-
<div class="text">
150-
{{range $i,$a := .AllThemes}}
151-
{{if eq $.SignedUser.Theme $a}}{{$a}}{{end}}
152-
{{end}}
153-
</div>
154-
155-
<div class="menu">
156-
{{range $i,$a := .AllThemes}}
157-
<div class="item{{if eq $.SignedUser.Theme $a}} active selected{{end}}" data-value="{{$a}}">
158-
{{$a}}
159-
</div>
160-
{{end}}
161-
</div>
162-
</div>
163-
</div>
164-
165-
<div class="field">
166-
<button class="ui green button">{{$.i18n.Tr "settings.update_theme"}}</button>
167-
</div>
168-
</form>
169-
</div>
170-
</div>
171133
<h4 class="ui top attached error header">
172134
{{.i18n.Tr "settings.delete_account"}}
173135
</h4>
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
{{template "base/head" .}}
2+
<div class="page-content user settings sshkeys">
3+
{{template "user/settings/navbar" .}}
4+
<div class="ui container">
5+
{{template "base/alert" .}}
6+
7+
<!-- Theme -->
8+
<h4 class="ui top attached header">
9+
{{.i18n.Tr "settings.manage_themes"}}
10+
</h4>
11+
<div class="ui attached segment">
12+
<div class="ui email list">
13+
<div class="item">
14+
{{.i18n.Tr "settings.theme_desc"}}
15+
</div>
16+
17+
<form class="ui form" action="{{.Link}}/theme" method="post">
18+
{{.CsrfTokenHtml}}
19+
<div class="field">
20+
<label for="ui">{{.i18n.Tr "settings.ui"}}</label>
21+
<div class="ui selection dropdown" id="ui">
22+
<input name="theme" type="hidden" value="{{.SignedUser.Theme}}">
23+
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
24+
<div class="text">
25+
{{range $i,$a := .AllThemes}}
26+
{{if eq $.SignedUser.Theme $a}}{{$a}}{{end}}
27+
{{end}}
28+
</div>
29+
30+
<div class="menu">
31+
{{range $i,$a := .AllThemes}}
32+
<div class="item{{if eq $.SignedUser.Theme $a}} active selected{{end}}" data-value="{{$a}}">
33+
{{$a}}
34+
</div>
35+
{{end}}
36+
</div>
37+
</div>
38+
</div>
39+
40+
<div class="field">
41+
<button class="ui green button">{{$.i18n.Tr "settings.update_theme"}}</button>
42+
</div>
43+
</form>
44+
</div>
45+
</div>
46+
47+
<!-- Language -->
48+
<h4 class="ui top attached header">
49+
{{.i18n.Tr "settings.language"}}
50+
</h4>
51+
<div class="ui attached segment">
52+
<form class="ui form" action="{{.Link}}/language" method="post">
53+
{{.CsrfTokenHtml}}
54+
<div class="field">
55+
<div class="ui language selection dropdown" id="language">
56+
<input name="language" type="hidden" value="{{.SignedUser.Language}}">
57+
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
58+
<div class="text">{{range .AllLangs}}{{if eq $.SignedUser.Language .Lang}}{{.Name}}{{end}}{{end}}</div>
59+
<div class="menu">
60+
{{range .AllLangs}}
61+
<div class="item{{if eq $.SignedUser.Language .Lang}} active selected{{end}}" data-value="{{.Lang}}">{{.Name}}</div>
62+
{{end}}
63+
</div>
64+
</div>
65+
</div>
66+
<div class="field">
67+
<button class="ui green button">{{$.i18n.Tr "settings.update_language"}}</button>
68+
</div>
69+
</form>
70+
</div>
71+
</div>
72+
</div>
73+
74+
{{template "base/footer" .}}

templates/user/settings/navbar.tmpl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
<a class="{{if .PageIsSettingsAccount}}active{{end}} item" href="{{AppSubUrl}}/user/settings/account">
77
{{.i18n.Tr "settings.account"}}
88
</a>
9+
<a class="{{if .PageIsSettingsAppearance}}active{{end}} item" href="{{AppSubUrl}}/user/settings/appearance">
10+
{{.i18n.Tr "settings.appearance"}}
11+
</a>
912
<a class="{{if .PageIsSettingsSecurity}}active{{end}} item" href="{{AppSubUrl}}/user/settings/security">
1013
{{.i18n.Tr "settings.security"}}
1114
</a>

templates/user/settings/profile.tmpl

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,20 +47,6 @@
4747
<input id="location" name="location" value="{{.SignedUser.Location}}">
4848
</div>
4949

50-
<div class="field">
51-
<label for="language">{{.i18n.Tr "settings.language"}}</label>
52-
<div class="ui language selection dropdown" id="language">
53-
<input name="language" type="hidden" value="{{.SignedUser.Language}}">
54-
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
55-
<div class="text">{{range .AllLangs}}{{if eq $.SignedUser.Language .Lang}}{{.Name}}{{end}}{{end}}</div>
56-
<div class="menu">
57-
{{range .AllLangs}}
58-
<div class="item{{if eq $.SignedUser.Language .Lang}} active selected{{end}}" data-value="{{.Lang}}">{{.Name}}</div>
59-
{{end}}
60-
</div>
61-
</div>
62-
</div>
63-
6450
<div class="ui divider"></div>
6551
<!-- private block -->
6652

0 commit comments

Comments
 (0)