mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-04-10 09:39:33 +00:00
454 lines
15 KiB
Elm
454 lines
15 KiB
Elm
{-
|
|
Copyright 2020 Eike K. & Contributors
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-or-later
|
|
-}
|
|
|
|
|
|
module Data.UiSettings exposing
|
|
( ItemPattern
|
|
, Pos(..)
|
|
, StoredUiSettings
|
|
, UiSettings
|
|
, cardPreviewSize
|
|
, cardPreviewSize2
|
|
, catColor
|
|
, catColorFg2
|
|
, catColorString2
|
|
, defaults
|
|
, fieldHidden
|
|
, fieldVisible
|
|
, merge
|
|
, mergeDefaults
|
|
, pdfUrl
|
|
, posFromString
|
|
, posToString
|
|
, storedUiSettingsDecoder
|
|
, storedUiSettingsEncode
|
|
, tagColor
|
|
, tagColorFg2
|
|
, tagColorString2
|
|
, toStoredUiSettings
|
|
)
|
|
|
|
import Api.Model.Tag exposing (Tag)
|
|
import Data.BasicSize exposing (BasicSize)
|
|
import Data.Color exposing (Color)
|
|
import Data.Fields exposing (Field)
|
|
import Data.Flags exposing (Flags)
|
|
import Data.ItemArrange exposing (ItemArrange)
|
|
import Data.ItemTemplate exposing (ItemTemplate)
|
|
import Data.Pdf exposing (PdfMode)
|
|
import Data.UiTheme exposing (UiTheme)
|
|
import Dict exposing (Dict)
|
|
import Html exposing (Attribute)
|
|
import Html.Attributes as HA
|
|
import Json.Decode as Decode
|
|
import Json.Decode.Pipeline as P
|
|
import Json.Encode as Encode
|
|
import Messages
|
|
import Messages.UiLanguage exposing (UiLanguage)
|
|
|
|
|
|
{-| Settings for the web ui. All fields should be optional, since it
|
|
is loaded from the server and mus be backward compatible.
|
|
|
|
Making fields optional, allows it to evolve without breaking previous
|
|
versions. Also if a user is logged out, an empty object is send to
|
|
force default settings.
|
|
|
|
-}
|
|
type alias StoredUiSettings =
|
|
{ itemSearchPageSize : Maybe Int
|
|
, tagCategoryColors : List ( String, String )
|
|
, pdfMode : Maybe String
|
|
, itemSearchNoteLength : Maybe Int
|
|
, itemDetailNotesPosition : Maybe String
|
|
, searchMenuFolderCount : Maybe Int
|
|
, searchMenuTagCount : Maybe Int
|
|
, searchMenuTagCatCount : Maybe Int
|
|
, formFields : Maybe (List String)
|
|
, itemDetailShortcuts : Bool
|
|
, searchMenuVisible : Bool
|
|
, editMenuVisible : Bool
|
|
, cardPreviewSize : Maybe String
|
|
, cardTitleTemplate : Maybe String
|
|
, cardSubtitleTemplate : Maybe String
|
|
, searchStatsVisible : Bool
|
|
, cardPreviewFullWidth : Bool
|
|
, uiTheme : Maybe String
|
|
, sideMenuVisible : Bool
|
|
, powerSearchEnabled : Bool
|
|
, uiLang : Maybe String
|
|
, itemSearchShowGroups : Bool
|
|
, itemSearchArrange : Maybe String
|
|
}
|
|
|
|
|
|
storedUiSettingsDecoder : Decode.Decoder StoredUiSettings
|
|
storedUiSettingsDecoder =
|
|
let
|
|
maybeInt =
|
|
Decode.maybe Decode.int
|
|
|
|
maybeString =
|
|
Decode.maybe Decode.string
|
|
in
|
|
Decode.succeed StoredUiSettings
|
|
|> P.optional "itemSearchPageSize" maybeInt Nothing
|
|
|> P.optional "tagCategoryColors" (Decode.keyValuePairs Decode.string) []
|
|
|> P.optional "pdfMode" maybeString Nothing
|
|
|> P.optional "itemSearchNoteLength" maybeInt Nothing
|
|
|> P.optional "itemDetailNotesPosition" maybeString Nothing
|
|
|> P.optional "searchMenuFolderCount" maybeInt Nothing
|
|
|> P.optional "searchMenuTagCount" maybeInt Nothing
|
|
|> P.optional "searchMenuTagCatCount" maybeInt Nothing
|
|
|> P.optional "formFields" (Decode.maybe <| Decode.list Decode.string) Nothing
|
|
|> P.optional "itemDetailShortcuts" Decode.bool False
|
|
|> P.optional "searchMenuVisible" Decode.bool False
|
|
|> P.optional "editMenuVisible" Decode.bool False
|
|
|> P.optional "cardPreviewSize" maybeString Nothing
|
|
|> P.optional "cardTitleTemplate" maybeString Nothing
|
|
|> P.optional "cardSubtitleTemplate" maybeString Nothing
|
|
|> P.optional "searchStatsVisible" Decode.bool False
|
|
|> P.optional "cardPreviewFullWidth" Decode.bool False
|
|
|> P.optional "uiTheme" maybeString Nothing
|
|
|> P.optional "sideMenuVisible" Decode.bool False
|
|
|> P.optional "powerSearchEnabled" Decode.bool False
|
|
|> P.optional "uiLang" maybeString Nothing
|
|
|> P.optional "itemSearchShowGroups" Decode.bool True
|
|
|> P.optional "itemSearchArrange" maybeString Nothing
|
|
|
|
|
|
storedUiSettingsEncode : StoredUiSettings -> Encode.Value
|
|
storedUiSettingsEncode value =
|
|
let
|
|
maybeEnc enca ma =
|
|
Maybe.map enca ma |> Maybe.withDefault Encode.null
|
|
in
|
|
Encode.object
|
|
[ ( "itemSearchPageSize", maybeEnc Encode.int value.itemSearchPageSize )
|
|
, ( "tagCategoryColors", Encode.dict identity Encode.string (Dict.fromList value.tagCategoryColors) )
|
|
, ( "pdfMode", maybeEnc Encode.string value.pdfMode )
|
|
, ( "itemSearchNoteLength", maybeEnc Encode.int value.itemSearchNoteLength )
|
|
, ( "itemDetailNotesPosition", maybeEnc Encode.string value.itemDetailNotesPosition )
|
|
, ( "searchMenuFolderCount", maybeEnc Encode.int value.searchMenuFolderCount )
|
|
, ( "searchMenuTagCount", maybeEnc Encode.int value.searchMenuTagCount )
|
|
, ( "searchMenuTagCatCount", maybeEnc Encode.int value.searchMenuTagCatCount )
|
|
, ( "formFields", maybeEnc (Encode.list Encode.string) value.formFields )
|
|
, ( "itemDetailShortcuts", Encode.bool value.itemDetailShortcuts )
|
|
, ( "searchMenuVisible", Encode.bool value.searchMenuVisible )
|
|
, ( "editMenuVisible", Encode.bool value.editMenuVisible )
|
|
, ( "cardPreviewSize", maybeEnc Encode.string value.cardPreviewSize )
|
|
, ( "cardTitleTemplate", maybeEnc Encode.string value.cardTitleTemplate )
|
|
, ( "cardSubtitleTemplate", maybeEnc Encode.string value.cardSubtitleTemplate )
|
|
, ( "searchStatsVisible", Encode.bool value.searchStatsVisible )
|
|
, ( "cardPreviewFullWidth", Encode.bool value.cardPreviewFullWidth )
|
|
, ( "uiTheme", maybeEnc Encode.string value.uiTheme )
|
|
, ( "sideMenuVisible", Encode.bool value.sideMenuVisible )
|
|
, ( "powerSearchEnabled", Encode.bool value.powerSearchEnabled )
|
|
, ( "uiLang", maybeEnc Encode.string value.uiLang )
|
|
, ( "itemSearchShowGroups", Encode.bool value.itemSearchShowGroups )
|
|
, ( "itemSearchArrange", maybeEnc Encode.string value.itemSearchArrange )
|
|
]
|
|
|
|
|
|
{-| Settings for the web ui. These fields are all mandatory, since
|
|
there is always a default value.
|
|
|
|
When loaded from local storage or the server, all optional fields can
|
|
fallback to a default value, converting the StoredUiSettings into a
|
|
UiSettings.
|
|
|
|
-}
|
|
type alias UiSettings =
|
|
{ itemSearchPageSize : Int
|
|
, tagCategoryColors : Dict String Color
|
|
, pdfMode : PdfMode
|
|
, itemSearchNoteLength : Int
|
|
, itemDetailNotesPosition : Pos
|
|
, searchMenuFolderCount : Int
|
|
, searchMenuTagCount : Int
|
|
, searchMenuTagCatCount : Int
|
|
, formFields : List Field
|
|
, itemDetailShortcuts : Bool
|
|
, searchMenuVisible : Bool
|
|
, editMenuVisible : Bool
|
|
, cardPreviewSize : BasicSize
|
|
, cardTitleTemplate : ItemPattern
|
|
, cardSubtitleTemplate : ItemPattern
|
|
, searchStatsVisible : Bool
|
|
, cardPreviewFullWidth : Bool
|
|
, uiTheme : UiTheme
|
|
, sideMenuVisible : Bool
|
|
, powerSearchEnabled : Bool
|
|
, uiLang : UiLanguage
|
|
, itemSearchShowGroups : Bool
|
|
, itemSearchArrange : ItemArrange
|
|
}
|
|
|
|
|
|
type alias ItemPattern =
|
|
{ pattern : String
|
|
, template : ItemTemplate
|
|
}
|
|
|
|
|
|
readPattern : String -> Maybe ItemPattern
|
|
readPattern str =
|
|
Data.ItemTemplate.readTemplate str
|
|
|> Maybe.map (ItemPattern str)
|
|
|
|
|
|
type Pos
|
|
= Top
|
|
| Bottom
|
|
|
|
|
|
posToString : Pos -> String
|
|
posToString pos =
|
|
case pos of
|
|
Top ->
|
|
"top"
|
|
|
|
Bottom ->
|
|
"bottom"
|
|
|
|
|
|
posFromString : String -> Maybe Pos
|
|
posFromString str =
|
|
case str of
|
|
"top" ->
|
|
Just Top
|
|
|
|
"bottom" ->
|
|
Just Bottom
|
|
|
|
_ ->
|
|
Nothing
|
|
|
|
|
|
defaults : UiSettings
|
|
defaults =
|
|
{ itemSearchPageSize = 60
|
|
, tagCategoryColors = Dict.empty
|
|
, pdfMode = Data.Pdf.Detect
|
|
, itemSearchNoteLength = 0
|
|
, itemDetailNotesPosition = Bottom
|
|
, searchMenuFolderCount = 3
|
|
, searchMenuTagCount = 6
|
|
, searchMenuTagCatCount = 3
|
|
, formFields = Data.Fields.all
|
|
, itemDetailShortcuts = False
|
|
, searchMenuVisible = False
|
|
, editMenuVisible = False
|
|
, cardPreviewSize = Data.BasicSize.Medium
|
|
, cardTitleTemplate =
|
|
{ template = Data.ItemTemplate.name
|
|
, pattern = "{{name}}"
|
|
}
|
|
, cardSubtitleTemplate =
|
|
{ template = Data.ItemTemplate.dateLong
|
|
, pattern = "{{dateLong}}"
|
|
}
|
|
, searchStatsVisible = True
|
|
, cardPreviewFullWidth = False
|
|
, uiTheme = Data.UiTheme.Light
|
|
, sideMenuVisible = True
|
|
, powerSearchEnabled = False
|
|
, uiLang = Messages.UiLanguage.English
|
|
, itemSearchShowGroups = True
|
|
, itemSearchArrange = Data.ItemArrange.Cards
|
|
}
|
|
|
|
|
|
merge : StoredUiSettings -> UiSettings -> UiSettings
|
|
merge given fallback =
|
|
{ itemSearchPageSize =
|
|
choose given.itemSearchPageSize fallback.itemSearchPageSize
|
|
, tagCategoryColors =
|
|
Dict.union
|
|
(Dict.fromList given.tagCategoryColors
|
|
|> Dict.map (\_ -> Data.Color.fromString)
|
|
|> Dict.filter (\_ -> \mc -> mc /= Nothing)
|
|
|> Dict.map (\_ -> Maybe.withDefault Data.Color.Grey)
|
|
)
|
|
fallback.tagCategoryColors
|
|
, pdfMode =
|
|
given.pdfMode
|
|
|> Maybe.andThen Data.Pdf.fromString
|
|
|> Maybe.withDefault fallback.pdfMode
|
|
, itemSearchNoteLength =
|
|
choose given.itemSearchNoteLength fallback.itemSearchNoteLength
|
|
, itemDetailNotesPosition =
|
|
choose (Maybe.andThen posFromString given.itemDetailNotesPosition)
|
|
fallback.itemDetailNotesPosition
|
|
, searchMenuFolderCount =
|
|
choose given.searchMenuFolderCount
|
|
fallback.searchMenuFolderCount
|
|
, searchMenuTagCount =
|
|
choose given.searchMenuTagCount fallback.searchMenuTagCount
|
|
, searchMenuTagCatCount =
|
|
choose given.searchMenuTagCatCount fallback.searchMenuTagCatCount
|
|
, formFields =
|
|
choose
|
|
(Maybe.map Data.Fields.fromList given.formFields)
|
|
fallback.formFields
|
|
, itemDetailShortcuts = given.itemDetailShortcuts
|
|
, searchMenuVisible = given.searchMenuVisible
|
|
, editMenuVisible = given.editMenuVisible
|
|
, cardPreviewSize =
|
|
given.cardPreviewSize
|
|
|> Maybe.andThen Data.BasicSize.fromString
|
|
|> Maybe.withDefault fallback.cardPreviewSize
|
|
, cardTitleTemplate =
|
|
Maybe.andThen readPattern given.cardTitleTemplate
|
|
|> Maybe.withDefault fallback.cardTitleTemplate
|
|
, cardSubtitleTemplate =
|
|
Maybe.andThen readPattern given.cardSubtitleTemplate
|
|
|> Maybe.withDefault fallback.cardSubtitleTemplate
|
|
, searchStatsVisible = given.searchStatsVisible
|
|
, cardPreviewFullWidth = given.cardPreviewFullWidth
|
|
, uiTheme =
|
|
Maybe.andThen Data.UiTheme.fromString given.uiTheme
|
|
|> Maybe.withDefault fallback.uiTheme
|
|
, sideMenuVisible = given.sideMenuVisible
|
|
, powerSearchEnabled = given.powerSearchEnabled
|
|
, uiLang =
|
|
Maybe.map Messages.fromIso2 given.uiLang
|
|
|> Maybe.withDefault Messages.UiLanguage.English
|
|
, itemSearchShowGroups = given.itemSearchShowGroups
|
|
, itemSearchArrange =
|
|
Maybe.andThen Data.ItemArrange.fromString given.itemSearchArrange
|
|
|> Maybe.withDefault fallback.itemSearchArrange
|
|
}
|
|
|
|
|
|
mergeDefaults : StoredUiSettings -> UiSettings
|
|
mergeDefaults given =
|
|
merge given defaults
|
|
|
|
|
|
toStoredUiSettings : UiSettings -> StoredUiSettings
|
|
toStoredUiSettings settings =
|
|
{ itemSearchPageSize = Just settings.itemSearchPageSize
|
|
, tagCategoryColors =
|
|
Dict.map (\_ -> Data.Color.toString) settings.tagCategoryColors
|
|
|> Dict.toList
|
|
, pdfMode = Just (Data.Pdf.asString settings.pdfMode)
|
|
, itemSearchNoteLength = Just settings.itemSearchNoteLength
|
|
, itemDetailNotesPosition = Just (posToString settings.itemDetailNotesPosition)
|
|
, searchMenuFolderCount = Just settings.searchMenuFolderCount
|
|
, searchMenuTagCount = Just settings.searchMenuTagCount
|
|
, searchMenuTagCatCount = Just settings.searchMenuTagCatCount
|
|
, formFields =
|
|
List.map Data.Fields.toString settings.formFields
|
|
|> Just
|
|
, itemDetailShortcuts = settings.itemDetailShortcuts
|
|
, searchMenuVisible = settings.searchMenuVisible
|
|
, editMenuVisible = settings.editMenuVisible
|
|
, cardPreviewSize =
|
|
settings.cardPreviewSize
|
|
|> Data.BasicSize.asString
|
|
|> Just
|
|
, cardTitleTemplate = settings.cardTitleTemplate.pattern |> Just
|
|
, cardSubtitleTemplate = settings.cardSubtitleTemplate.pattern |> Just
|
|
, searchStatsVisible = settings.searchStatsVisible
|
|
, cardPreviewFullWidth = settings.cardPreviewFullWidth
|
|
, uiTheme = Just (Data.UiTheme.toString settings.uiTheme)
|
|
, sideMenuVisible = settings.sideMenuVisible
|
|
, powerSearchEnabled = settings.powerSearchEnabled
|
|
, uiLang = Just <| Messages.toIso2 settings.uiLang
|
|
, itemSearchShowGroups = settings.itemSearchShowGroups
|
|
, itemSearchArrange = Data.ItemArrange.asString settings.itemSearchArrange |> Just
|
|
}
|
|
|
|
|
|
catColor : UiSettings -> String -> Maybe Color
|
|
catColor settings c =
|
|
Dict.get c settings.tagCategoryColors
|
|
|
|
|
|
tagColor : Tag -> UiSettings -> Maybe Color
|
|
tagColor tag settings =
|
|
Maybe.andThen (catColor settings) tag.category
|
|
|
|
|
|
catColorString2 : UiSettings -> String -> String
|
|
catColorString2 settings name =
|
|
catColor settings name
|
|
|> Maybe.map Data.Color.toString2
|
|
|> Maybe.withDefault ""
|
|
|
|
|
|
catColorFg2 : UiSettings -> String -> String
|
|
catColorFg2 settings name =
|
|
catColor settings name
|
|
|> Maybe.map Data.Color.toStringFg2
|
|
|> Maybe.withDefault ""
|
|
|
|
|
|
tagColorString2 : Tag -> UiSettings -> String
|
|
tagColorString2 tag settings =
|
|
tagColor tag settings
|
|
|> Maybe.map Data.Color.toString2
|
|
|> Maybe.withDefault "border-black dark:border-bluegray-200"
|
|
|
|
|
|
tagColorFg2 : Tag -> UiSettings -> String
|
|
tagColorFg2 tag settings =
|
|
tagColor tag settings
|
|
|> Maybe.map Data.Color.toStringFg2
|
|
|> Maybe.withDefault ""
|
|
|
|
|
|
fieldVisible : UiSettings -> Field -> Bool
|
|
fieldVisible settings field =
|
|
List.member field settings.formFields
|
|
|
|
|
|
fieldHidden : UiSettings -> Field -> Bool
|
|
fieldHidden settings field =
|
|
fieldVisible settings field |> not
|
|
|
|
|
|
cardPreviewSize : UiSettings -> Attribute msg
|
|
cardPreviewSize settings =
|
|
Data.BasicSize.asString settings.cardPreviewSize
|
|
|> HA.class
|
|
|
|
|
|
cardPreviewSize2 : UiSettings -> String
|
|
cardPreviewSize2 settings =
|
|
case settings.cardPreviewSize of
|
|
Data.BasicSize.Small ->
|
|
"max-h-16"
|
|
|
|
Data.BasicSize.Medium ->
|
|
"max-h-52"
|
|
|
|
Data.BasicSize.Large ->
|
|
"max-h-80"
|
|
|
|
|
|
pdfUrl : UiSettings -> Flags -> String -> String
|
|
pdfUrl settings flags originalUrl =
|
|
case settings.pdfMode of
|
|
Data.Pdf.Detect ->
|
|
Data.Pdf.detectUrl flags originalUrl
|
|
|
|
Data.Pdf.Native ->
|
|
originalUrl
|
|
|
|
Data.Pdf.Server ->
|
|
Data.Pdf.serverUrl originalUrl
|
|
|
|
|
|
|
|
--- Helpers
|
|
|
|
|
|
choose : Maybe a -> a -> a
|
|
choose m1 m2 =
|
|
Maybe.withDefault m2 m1
|