/* * Copyright (C) 2026 Mateusz GruszczyƄski @linuxiarz.pl * Source-Available Code / Dual-Licensed. * * Free for non-commercial and evaluation use under terms of BSL/GPLv3. * Commercial or production use requires a valid paid license. * See LICENSE file in repository root for details. */ use super::*; #[derive(Debug, Clone, Serialize)] pub struct EditorPreferences { pub compact_view: bool, pub editor_line_numbers: bool, pub preview_line_numbers: bool, pub line_links: bool, pub toolbar_collapsed: bool, pub navbar_collapsed: bool, pub font_family: String, pub font_size: i64, } impl Default for EditorPreferences { fn default() -> Self { Self { compact_view: true, editor_line_numbers: true, preview_line_numbers: false, line_links: false, toolbar_collapsed: false, navbar_collapsed: false, font_family: "mono".into(), font_size: 14, } } } #[derive(Debug, Clone, Serialize)] pub struct ResourceEditorSettings { pub authorship_mode: String, pub colors_enabled: bool, } impl Default for ResourceEditorSettings { fn default() -> Self { Self { authorship_mode: "simple".into(), colors_enabled: true, } } } #[derive(Debug, Clone, Copy)] pub enum EditorPreferenceResource { Pad(i64), Note(i64), } fn preference_select_query(resource: EditorPreferenceResource) -> queries::Query { match resource { EditorPreferenceResource::Pad(_) => queries::EDITOR_PREFERENCES_SELECT_PAD, EditorPreferenceResource::Note(_) => queries::EDITOR_PREFERENCES_SELECT_NOTE, } } fn preference_upsert_query(resource: EditorPreferenceResource) -> queries::Query { match resource { EditorPreferenceResource::Pad(_) => queries::EDITOR_PREFERENCES_UPSERT_PAD, EditorPreferenceResource::Note(_) => queries::EDITOR_PREFERENCES_UPSERT_NOTE, } } fn resource_id(resource: EditorPreferenceResource) -> i64 { match resource { EditorPreferenceResource::Pad(id) | EditorPreferenceResource::Note(id) => id, } } pub async fn load_editor_preferences( pool: &Database, user_id: i64, resource: EditorPreferenceResource, ) -> Result, sqlx::Error> { let Some(row) = sqlx::query(queries::get(pool.kind(), preference_select_query(resource))) .bind(user_id) .bind(resource_id(resource)) .fetch_optional(pool.pool()) .await? else { return Ok(None); }; Ok(Some(EditorPreferences { compact_view: row.try_get::(0)? != 0, editor_line_numbers: row.try_get::(1)? != 0, preview_line_numbers: row.try_get::(2)? != 0, line_links: row.try_get::(3)? != 0, toolbar_collapsed: row.try_get::(4)? != 0, navbar_collapsed: row.try_get::(5)? != 0, font_family: crate::row_decode::text(&row, 6)?, font_size: row.try_get(7)?, })) } pub async fn save_editor_configuration( pool: &Database, user_id: Option, resource: EditorPreferenceResource, preferences: Option<&EditorPreferences>, resource_settings: Option<(&str, &str, &ResourceEditorSettings)>, ) -> Result<(), sqlx::Error> { let mut tx = pool.pool().begin().await?; if let Some(preferences) = preferences { let user_id = user_id.ok_or_else(|| { sqlx::Error::Protocol("user id is required for personal editor preferences".into()) })?; sqlx::query(queries::get(pool.kind(), preference_upsert_query(resource))) .bind(user_id) .bind(resource_id(resource)) .bind(preferences.compact_view) .bind(preferences.editor_line_numbers) .bind(preferences.preview_line_numbers) .bind(preferences.line_links) .bind(preferences.toolbar_collapsed) .bind(preferences.navbar_collapsed) .bind(&preferences.font_family) .bind(preferences.font_size) .execute(&mut *tx) .await?; } if let Some((resource_kind, resource_slug, settings)) = resource_settings { sqlx::query(queries::get( pool.kind(), queries::RESOURCE_EDITOR_SETTINGS_UPSERT, )) .bind(resource_kind) .bind(resource_slug) .bind(&settings.authorship_mode) .bind(settings.colors_enabled) .execute(&mut *tx) .await?; } tx.commit().await?; Ok(()) } pub async fn load_resource_editor_settings( pool: &Database, resource_kind: &str, resource_slug: &str, ) -> Result { let Some(row) = sqlx::query(queries::get( pool.kind(), queries::RESOURCE_EDITOR_SETTINGS_SELECT, )) .bind(resource_kind) .bind(resource_slug) .fetch_optional(pool.pool()) .await? else { return Ok(ResourceEditorSettings::default()); }; Ok(ResourceEditorSettings { authorship_mode: crate::row_decode::text(&row, 0)?, colors_enabled: row.try_get::(1)? != 0, }) } pub async fn delete_resource_editor_state( pool: &Database, resource_kind: &str, resource_slug: &str, ) -> Result<(), sqlx::Error> { let mut tx = pool.pool().begin().await?; sqlx::query(queries::get( pool.kind(), queries::RESOURCE_COLORS_DELETE_BY_RESOURCE, )) .bind(resource_kind) .bind(resource_slug) .execute(&mut *tx) .await?; sqlx::query(queries::get( pool.kind(), queries::RESOURCE_EDITOR_SETTINGS_DELETE, )) .bind(resource_kind) .bind(resource_slug) .execute(&mut *tx) .await?; tx.commit().await?; Ok(()) }