themeing
This commit is contained in:
		| @@ -1,5 +1,10 @@ | ||||
| package de.jottyfan.bico.modules; | ||||
|  | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.ui.Model; | ||||
|  | ||||
| import de.jottyfan.bico.modules.profile.ProfileService; | ||||
|  | ||||
| /** | ||||
|  * | ||||
|  * @author jotty | ||||
| @@ -7,4 +12,18 @@ package de.jottyfan.bico.modules; | ||||
|  */ | ||||
| public abstract class CommonController { | ||||
|  | ||||
| 	@Autowired | ||||
| 	private ProfileService profileService; | ||||
|  | ||||
| 	/** | ||||
| 	 * get the theme for the current session | ||||
| 	 * | ||||
| 	 * @return the theme; light or dark at the moment | ||||
| 	 */ | ||||
| 	public Model useThemedModel(Model model) { | ||||
| 		// TODO: add profile's user name | ||||
| 		String username = "jotty"; | ||||
| 		model.addAttribute("theme", profileService.getTheme(username)); | ||||
| 		return model; | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| package de.jottyfan.bico.modules.index; | ||||
|  | ||||
| import org.springframework.stereotype.Controller; | ||||
| import org.springframework.ui.Model; | ||||
| import org.springframework.web.bind.annotation.GetMapping; | ||||
|  | ||||
| import de.jottyfan.bico.modules.CommonController; | ||||
| @@ -13,7 +14,8 @@ import de.jottyfan.bico.modules.CommonController; | ||||
| @Controller | ||||
| public class IndexController extends CommonController { | ||||
| 	@GetMapping("/") | ||||
| 	public String getIndex() { | ||||
| 	public String getIndex(Model model) { | ||||
| 		useThemedModel(model); | ||||
| 		return "redirect:/sheet"; | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,35 @@ | ||||
| package de.jottyfan.bico.modules.profile; | ||||
|  | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.http.ResponseEntity; | ||||
| import org.springframework.web.bind.annotation.PathVariable; | ||||
| import org.springframework.web.bind.annotation.PostMapping; | ||||
| import org.springframework.web.bind.annotation.RestController; | ||||
|  | ||||
| import de.jottyfan.bico.modules.CommonController; | ||||
|  | ||||
| /** | ||||
|  * | ||||
|  * @author jotty | ||||
|  * | ||||
|  */ | ||||
| @RestController | ||||
| public class ProfileController extends CommonController { | ||||
|  | ||||
| 	@Autowired | ||||
| 	private ProfileService service; | ||||
|  | ||||
| 	/** | ||||
| 	 * update the theme of the current user | ||||
| 	 * | ||||
| 	 * @param theme the theme | ||||
| 	 */ | ||||
| 	@PostMapping("/updateTheme/{theme}") | ||||
| 	public ResponseEntity<?> updateTheme(@PathVariable String theme) { | ||||
| 		// TODO: add profile's user name | ||||
| 		String username = "jotty"; | ||||
| 		service.updateTheme(username, theme); | ||||
| 		return ResponseEntity.ok(null); | ||||
| 	} | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,70 @@ | ||||
| package de.jottyfan.bico.modules.profile; | ||||
|  | ||||
| import static de.jottyfan.bico.db.Tables.T_PROFILE; | ||||
|  | ||||
| import org.apache.logging.log4j.LogManager; | ||||
| import org.apache.logging.log4j.Logger; | ||||
| import org.jooq.DSLContext; | ||||
| import org.jooq.InsertOnDuplicateSetMoreStep; | ||||
| import org.jooq.SelectConditionStep; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.stereotype.Repository; | ||||
|  | ||||
| import de.jottyfan.bico.db.tables.records.TProfileRecord; | ||||
| import de.jottyfan.bico.modules.profile.model.ProfileBean; | ||||
|  | ||||
| /** | ||||
|  * | ||||
|  * @author jotty | ||||
|  * | ||||
|  */ | ||||
| @Repository | ||||
| public class ProfileRepository { | ||||
| 	private static final Logger LOGGER = LogManager.getLogger(ProfileRepository.class); | ||||
|  | ||||
| 	@Autowired | ||||
| 	private DSLContext jooq; | ||||
|  | ||||
| 	/** | ||||
| 	 * get the profile of the user | ||||
| 	 * | ||||
| 	 * @param username the name of the user | ||||
| 	 * @return the profile or null if not found | ||||
| 	 */ | ||||
| 	public ProfileBean getProfile(String username) { | ||||
| 		SelectConditionStep<TProfileRecord> sql = jooq | ||||
| 		// @formatter:off | ||||
| 			.selectFrom(T_PROFILE) | ||||
| 			.where(T_PROFILE.USERNAME.eq(username)); | ||||
| 		// @formatter:on | ||||
| 		LOGGER.trace(sql.toString()); | ||||
| 		TProfileRecord r = sql.fetchOne(); | ||||
| 		if (r != null) { | ||||
| 			return ProfileBean.of(username).withTheme(r.getTheme()); | ||||
| 		} else { | ||||
| 			return null; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * upsert theme for username | ||||
| 	 * | ||||
| 	 * @param username the name of the user | ||||
| 	 * @param theme    the selected theme; may be light or dark | ||||
| 	 * @return number of affected database rows; should be 1 | ||||
| 	 */ | ||||
| 	public Integer upsertTheme(String username, String theme) { | ||||
| 		InsertOnDuplicateSetMoreStep<TProfileRecord> sql = jooq | ||||
| 		// @formatter:off | ||||
| 			.insertInto(T_PROFILE, | ||||
| 					        T_PROFILE.USERNAME, | ||||
| 					        T_PROFILE.THEME) | ||||
| 			.values(username, theme) | ||||
| 			.onConflict(T_PROFILE.USERNAME) | ||||
| 			.doUpdate() | ||||
| 			.setAllToExcluded(); | ||||
| 		// @formatter:on | ||||
| 		LOGGER.trace(sql.toString()); | ||||
| 		return sql.execute(); | ||||
| 	} | ||||
| } | ||||
| @@ -0,0 +1,40 @@ | ||||
| package de.jottyfan.bico.modules.profile; | ||||
|  | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.stereotype.Service; | ||||
|  | ||||
| import de.jottyfan.bico.modules.profile.model.ProfileBean; | ||||
|  | ||||
| /** | ||||
|  * | ||||
|  * @author jotty | ||||
|  * | ||||
|  */ | ||||
| @Service | ||||
| public class ProfileService { | ||||
|  | ||||
| 	@Autowired | ||||
| 	private ProfileRepository repository; | ||||
|  | ||||
| 	/** | ||||
| 	 * get the theme of the user | ||||
| 	 * | ||||
| 	 * @param username the name of the user | ||||
| 	 * @return the theme of the user | ||||
| 	 */ | ||||
| 	public String getTheme(String username) { | ||||
| 		ProfileBean bean = repository.getProfile(username); | ||||
| 		return bean == null ? "light" : bean.getTheme(); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * update the theme of the user | ||||
| 	 * | ||||
| 	 * @param username the name of the user | ||||
| 	 * @param theme the theme; may be light or dark | ||||
| 	 */ | ||||
| 	public void updateTheme(String username, String theme) { | ||||
| 		repository.upsertTheme(username, theme); | ||||
| 	} | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,58 @@ | ||||
| package de.jottyfan.bico.modules.profile.model; | ||||
|  | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * | ||||
|  * @author jotty | ||||
|  * | ||||
|  */ | ||||
| public class ProfileBean implements Serializable { | ||||
| 	private static final long serialVersionUID = 1L; | ||||
|  | ||||
| 	private String username; | ||||
| 	private String theme; | ||||
|  | ||||
| 	public static final ProfileBean of(String username) { | ||||
| 		ProfileBean bean = new ProfileBean(); | ||||
| 		bean.setUsername(username); | ||||
| 		return bean; | ||||
| 	} | ||||
|  | ||||
| 	public static final ProfileBean of(String username, String theme) { | ||||
| 		return ProfileBean.of(username).withTheme(theme); | ||||
| 	} | ||||
|  | ||||
| 	public ProfileBean withTheme(String theme) { | ||||
| 		this.theme = theme; | ||||
| 		return this; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @return the username | ||||
| 	 */ | ||||
| 	public String getUsername() { | ||||
| 		return username; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @param username the username to set | ||||
| 	 */ | ||||
| 	public void setUsername(String username) { | ||||
| 		this.username = username; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @return the theme | ||||
| 	 */ | ||||
| 	public String getTheme() { | ||||
| 		return theme; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @param theme the theme to set | ||||
| 	 */ | ||||
| 	public void setTheme(String theme) { | ||||
| 		this.theme = theme; | ||||
| 	} | ||||
| } | ||||
| @@ -20,7 +20,7 @@ public class SheetController extends CommonController { | ||||
|  | ||||
| 	@GetMapping("/sheet") | ||||
| 	public String getSheet(Model model) { | ||||
| 		model.addAttribute("list", service.getList()); | ||||
| 		useThemedModel(model).addAttribute("list", service.getList()); | ||||
| 		return "/sheet"; | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,21 @@ | ||||
| toggleDarkMode = function() { | ||||
| 	var oldValue = $("html").attr("data-bs-theme"); | ||||
| 	var newValue = oldValue == "dark" ? "light" : "dark"; | ||||
| 	var updateUrl = /*[[@{/updateTheme}]]*/ 'updateTheme'; | ||||
| 	updateUrl = updateUrl + "/" + newValue; | ||||
| 	$("html").attr("data-bs-theme", newValue); | ||||
| 	$.ajax({ | ||||
| 		url: updateUrl, | ||||
| 		type: "POST", | ||||
| 		contentType: "application/json", | ||||
| 		dataType: 'json' | ||||
| 	}); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * only because th:data-bs-theme="${theme}" does not work | ||||
|  */ | ||||
| $(document).ready(function(){ | ||||
| 	var theme = /*[[${theme}]]*/ 'dark'; | ||||
| 	$("html").attr("data-bs-theme", theme); | ||||
| }); | ||||
|   | ||||
| @@ -1,9 +1,5 @@ | ||||
| <!DOCTYPE html> | ||||
| <html xmlns:th="http://www.thymeleaf.org" layout:decorate="~{template}" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:sec="http://www.thymeleaf.org/extras/spring-security"> | ||||
| <head> | ||||
| <title>Camp Organizer 2</title> | ||||
| <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | ||||
| </head> | ||||
| <body> | ||||
| 	<th:block layout:fragment="content"> | ||||
| 		<div class="borderdist"> | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| <!DOCTYPE html> | ||||
| <html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security" data-bs-theme="dark"> | ||||
| <html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security"> | ||||
| <head> | ||||
| <title>Camp Organizer 2</title> | ||||
| <title>Bible Class Organizer</title> | ||||
| <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | ||||
| <link th:rel="stylesheet" type="text/css" media="all" th:href="@{/webjars/bootstrap/5.3.1/css/bootstrap.min.css}" /> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user