Add a qr code to the link of an item or attachment

This commit is contained in:
eikek 2021-08-17 02:15:14 +02:00
parent 2d2f9e3e87
commit 8f23b68587
14 changed files with 307 additions and 41 deletions

View File

@ -38,6 +38,6 @@ update =
Comp.ItemDetail.Update.update Comp.ItemDetail.Update.update
view2 : Texts -> ItemNav -> UiSettings -> Model -> Html Msg view2 : Texts -> Flags -> ItemNav -> UiSettings -> Model -> Html Msg
view2 = view2 =
Comp.ItemDetail.View2.view Comp.ItemDetail.View2.view

View File

@ -18,7 +18,10 @@ module Comp.ItemDetail.Model exposing
, ViewMode(..) , ViewMode(..)
, emptyModel , emptyModel
, initSelectViewModel , initSelectViewModel
, initShowQrModel
, isEditNotes , isEditNotes
, isShowQrAttach
, isShowQrItem
, personMatchesOrg , personMatchesOrg
, resultModel , resultModel
, resultModelCmd , resultModelCmd
@ -40,7 +43,6 @@ import Api.Model.SentMails exposing (SentMails)
import Api.Model.Tag exposing (Tag) import Api.Model.Tag exposing (Tag)
import Api.Model.TagList exposing (TagList) import Api.Model.TagList exposing (TagList)
import Comp.AttachmentMeta import Comp.AttachmentMeta
import Comp.ConfirmModal
import Comp.CustomFieldMultiInput import Comp.CustomFieldMultiInput
import Comp.DatePicker import Comp.DatePicker
import Comp.DetailEdit import Comp.DetailEdit
@ -118,9 +120,33 @@ type alias Model =
, attachmentDropdownOpen : Bool , attachmentDropdownOpen : Bool
, editMenuTabsOpen : Set String , editMenuTabsOpen : Set String
, viewMode : ViewMode , viewMode : ViewMode
, showQrModel : ShowQrModel
} }
type alias ShowQrModel =
{ item : Bool
, attach : Bool
}
initShowQrModel : ShowQrModel
initShowQrModel =
{ item = False
, attach = False
}
isShowQrItem : ShowQrModel -> Bool
isShowQrItem model =
model.item
isShowQrAttach : ShowQrModel -> Bool
isShowQrAttach model =
model.attach
type ConfirmModalValue type ConfirmModalValue
= ConfirmModalReprocessItem Msg = ConfirmModalReprocessItem Msg
| ConfirmModalReprocessFile Msg | ConfirmModalReprocessFile Msg
@ -230,6 +256,7 @@ emptyModel =
, attachmentDropdownOpen = False , attachmentDropdownOpen = False
, editMenuTabsOpen = Set.empty , editMenuTabsOpen = Set.empty
, viewMode = SimpleView , viewMode = SimpleView
, showQrModel = initShowQrModel
} }
@ -340,6 +367,9 @@ type Msg
| ReprocessItemConfirmed | ReprocessItemConfirmed
| ToggleSelectView | ToggleSelectView
| RestoreItem | RestoreItem
| ToggleShowQrItem String
| ToggleShowQrAttach String
| PrintElement String
type SaveNameState type SaveNameState

View File

@ -0,0 +1,117 @@
{-
Copyright 2020 Docspell Contributors
SPDX-License-Identifier: GPL-3.0-or-later
-}
module Comp.ItemDetail.ShowQrCode exposing (UrlId(..), qrCodeElementId, view, view1)
import Api
import Comp.Basic as B
import Comp.ItemDetail.Model exposing (Model, Msg(..), isShowQrAttach, isShowQrItem)
import Comp.MenuBar as MB
import Data.Flags exposing (Flags)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onClick)
import QRCode
import Styles as S
view : Flags -> String -> Model -> UrlId -> Html Msg
view flags classes model urlId =
case urlId of
Attach _ ->
if isShowQrAttach model.showQrModel then
view1 flags classes urlId
else
span [ class "hidden" ] []
Item _ ->
if isShowQrItem model.showQrModel then
view1 flags classes urlId
else
span [ class "hidden" ] []
view1 : Flags -> String -> UrlId -> Html Msg
view1 flags classes urlId =
let
docUrl =
case urlId of
Attach str ->
flags.config.baseUrl ++ Api.fileURL str
Item str ->
flags.config.baseUrl ++ "/app/item/" ++ str
elementId =
qrCodeElementId urlId
toggleShowQr =
case urlId of
Attach id ->
ToggleShowQrAttach id
Item id ->
ToggleShowQrItem id
in
div
[ class "flex flex-col py-2 px-2 items-center"
, class classes
]
[ MB.view
{ start =
[ MB.PrimaryButton
{ tagger = PrintElement elementId
, title = "Print this QR code"
, icon = Just "fa fa-print"
, label = "Print"
}
]
, end =
[ MB.SecondaryButton
{ tagger = toggleShowQr
, title = "Close"
, icon = Just "fa fa-times"
, label = "Close"
}
]
, rootClasses = "w-full mt-2 mb-4"
}
, div [ class "flex flex-col sm:flex-row sm:space-x-2" ]
[ div
[ class S.border
, class S.qrCode
, id elementId
]
[ qrCodeView docUrl
]
]
]
qrCodeElementId : UrlId -> String
qrCodeElementId urlId =
case urlId of
Attach str ->
"qr-attach-" ++ str
Item str ->
"qr-item-" ++ str
type UrlId
= Attach String
| Item String
qrCodeView : String -> Html msg
qrCodeView message =
QRCode.encode message
|> Result.map QRCode.toSvg
|> Result.withDefault
(text "Error generating QR code")

View File

@ -11,8 +11,19 @@ import Api
import Api.Model.Attachment exposing (Attachment) import Api.Model.Attachment exposing (Attachment)
import Comp.AttachmentMeta import Comp.AttachmentMeta
import Comp.ItemDetail.ConfirmModalView import Comp.ItemDetail.ConfirmModalView
import Comp.ItemDetail.Model exposing (Model, Msg(..), NotesField(..), SaveNameState(..), ViewMode(..)) import Comp.ItemDetail.Model
exposing
( Model
, Msg(..)
, NotesField(..)
, SaveNameState(..)
, ViewMode(..)
, isShowQrAttach
)
import Comp.ItemDetail.ShowQrCode
import Comp.MenuBar as MB import Comp.MenuBar as MB
import Data.Flags exposing (Flags)
import Data.Icons as Icons
import Data.UiSettings exposing (UiSettings) import Data.UiSettings exposing (UiSettings)
import Dict import Dict
import Html exposing (..) import Html exposing (..)
@ -27,8 +38,8 @@ import Util.Size
import Util.String import Util.String
view : Texts -> UiSettings -> Model -> Int -> Attachment -> Html Msg view : Texts -> Flags -> UiSettings -> Model -> Int -> Attachment -> Html Msg
view texts settings model pos attach = view texts flags settings model pos attach =
let let
fileUrl = fileUrl =
Api.fileURL attach.id Api.fileURL attach.id
@ -61,6 +72,11 @@ view texts settings model pos attach =
Nothing -> Nothing ->
span [ class "hidden" ] [] span [ class "hidden" ] []
else if isShowQrAttach model.showQrModel then
Comp.ItemDetail.ShowQrCode.view1 flags
"border-r border-l border-b dark:border-bluegray-600 h-full"
(Comp.ItemDetail.ShowQrCode.Attach attach.id)
else else
div div
[ class "flex flex-col relative px-2 pt-2 h-full" [ class "flex flex-col relative px-2 pt-2 h-full"
@ -269,6 +285,13 @@ attachHeader texts settings model _ attach =
, href "#" , href "#"
] ]
} }
, { icon = Icons.showQr
, label = texts.showQrCode
, attrs =
[ onClick (ToggleShowQrAttach attach.id)
, href "#"
]
}
, { icon = "fa fa-trash" , { icon = "fa fa-trash"
, label = texts.deleteThisFile , label = texts.deleteThisFile
, attrs = , attrs =

View File

@ -42,7 +42,10 @@ import Comp.ItemDetail.Model
, UpdateResult , UpdateResult
, ViewMode(..) , ViewMode(..)
, initSelectViewModel , initSelectViewModel
, initShowQrModel
, isEditNotes , isEditNotes
, isShowQrAttach
, isShowQrItem
, resultModel , resultModel
, resultModelCmd , resultModelCmd
, resultModelCmdSub , resultModelCmdSub
@ -66,6 +69,7 @@ import Dict
import Html5.DragDrop as DD import Html5.DragDrop as DD
import Http import Http
import Page exposing (Page(..)) import Page exposing (Page(..))
import Ports
import Set exposing (Set) import Set exposing (Set)
import Throttle import Throttle
import Time import Time
@ -1607,6 +1611,29 @@ update key flags inav settings msg model =
RestoreItem -> RestoreItem ->
resultModelCmd ( model, Api.restoreItem flags model.item.id SaveResp ) resultModelCmd ( model, Api.restoreItem flags model.item.id SaveResp )
ToggleShowQrItem id ->
let
sqm =
model.showQrModel
next =
{ sqm | item = not sqm.item }
in
resultModel { model | showQrModel = next }
ToggleShowQrAttach id ->
let
sqm =
model.showQrModel
next =
{ sqm | attach = not sqm.attach }
in
resultModel { model | attachmentDropdownOpen = False, showQrModel = next }
PrintElement id ->
resultModelCmd ( model, Ports.printElement id )
--- Helper --- Helper

View File

@ -19,12 +19,15 @@ import Comp.ItemDetail.Model
, Msg(..) , Msg(..)
, NotesField(..) , NotesField(..)
, SaveNameState(..) , SaveNameState(..)
, isShowQrItem
) )
import Comp.ItemDetail.Notes import Comp.ItemDetail.Notes
import Comp.ItemDetail.ShowQrCode
import Comp.ItemDetail.SingleAttachment import Comp.ItemDetail.SingleAttachment
import Comp.ItemMail import Comp.ItemMail
import Comp.MenuBar as MB import Comp.MenuBar as MB
import Comp.SentMails import Comp.SentMails
import Data.Flags exposing (Flags)
import Data.Icons as Icons import Data.Icons as Icons
import Data.ItemNav exposing (ItemNav) import Data.ItemNav exposing (ItemNav)
import Data.UiSettings exposing (UiSettings) import Data.UiSettings exposing (UiSettings)
@ -36,12 +39,12 @@ import Page exposing (Page(..))
import Styles as S import Styles as S
view : Texts -> ItemNav -> UiSettings -> Model -> Html Msg view : Texts -> Flags -> ItemNav -> UiSettings -> Model -> Html Msg
view texts inav settings model = view texts flags inav settings model =
div [ class "flex flex-col h-full" ] div [ class "flex flex-col h-full" ]
[ header texts settings model [ header texts settings model
, menuBar texts inav settings model , menuBar texts inav settings model
, body texts inav settings model , body texts flags inav settings model
, itemModal texts model , itemModal texts model
] ]
@ -146,7 +149,7 @@ menuBar texts inav settings model =
[ ( "bg-gray-200 dark:bg-bluegray-600", model.addFilesOpen ) [ ( "bg-gray-200 dark:bg-bluegray-600", model.addFilesOpen )
] ]
, if model.addFilesOpen then , if model.addFilesOpen then
title "Close" title texts.close
else else
title texts.addMoreFiles title texts.addMoreFiles
@ -156,6 +159,22 @@ menuBar texts inav settings model =
] ]
[ Icons.addFilesIcon2 "" [ Icons.addFilesIcon2 ""
] ]
, MB.CustomElement <|
a
[ classList
[ ( "bg-gray-200 dark:bg-bluegray-600", isShowQrItem model.showQrModel )
]
, if isShowQrItem model.showQrModel then
title texts.close
else
title texts.showQrCode
, onClick (ToggleShowQrItem model.item.id)
, class S.secondaryBasicButton
, href "#"
]
[ Icons.showQrIcon ""
]
, MB.CustomElement <| , MB.CustomElement <|
a a
[ class S.primaryButton [ class S.primaryButton
@ -214,20 +233,24 @@ menuBar texts inav settings model =
} }
body : Texts -> ItemNav -> UiSettings -> Model -> Html Msg body : Texts -> Flags -> ItemNav -> UiSettings -> Model -> Html Msg
body texts _ settings model = body texts flags _ settings model =
div [ class "grid gap-2 grid-cols-1 md:grid-cols-3 h-full" ] div [ class "grid gap-2 grid-cols-1 md:grid-cols-3 h-full" ]
[ leftArea texts settings model [ leftArea texts flags settings model
, rightArea texts settings model , rightArea texts flags settings model
] ]
leftArea : Texts -> UiSettings -> Model -> Html Msg leftArea : Texts -> Flags -> UiSettings -> Model -> Html Msg
leftArea texts settings model = leftArea texts flags settings model =
div [ class "w-full md:order-first md:mr-2 flex flex-col" ] div [ class "w-full md:order-first md:mr-2 flex flex-col" ]
[ addDetailForm texts settings model [ addDetailForm texts settings model
, sendMailForm texts settings model , sendMailForm texts settings model
, Comp.ItemDetail.AddFilesForm.view texts.addFilesForm model , Comp.ItemDetail.AddFilesForm.view texts.addFilesForm model
, Comp.ItemDetail.ShowQrCode.view flags
(S.border ++ " mb-4")
model
(Comp.ItemDetail.ShowQrCode.Item model.item.id)
, Comp.ItemDetail.Notes.view texts.notes model , Comp.ItemDetail.Notes.view texts.notes model
, div , div
[ classList [ classList
@ -245,15 +268,15 @@ leftArea texts settings model =
] ]
rightArea : Texts -> UiSettings -> Model -> Html Msg rightArea : Texts -> Flags -> UiSettings -> Model -> Html Msg
rightArea texts settings model = rightArea texts flags settings model =
div [ class "md:col-span-2 h-full" ] div [ class "md:col-span-2 h-full" ]
(attachmentsBody texts settings model) (attachmentsBody texts flags settings model)
attachmentsBody : Texts -> UiSettings -> Model -> List (Html Msg) attachmentsBody : Texts -> Flags -> UiSettings -> Model -> List (Html Msg)
attachmentsBody texts settings model = attachmentsBody texts flags settings model =
List.indexedMap (Comp.ItemDetail.SingleAttachment.view texts.singleAttachment settings model) List.indexedMap (Comp.ItemDetail.SingleAttachment.view texts.singleAttachment flags settings model)
model.item.attachments model.item.attachments

View File

@ -279,9 +279,6 @@ viewLinks2 texts flags _ source =
styleUrl = styleUrl =
"truncate px-2 py-2 border-0 border-t border-b border-r font-mono text-sm my-auto rounded-r border-gray-400 dark:border-bluegray-500" "truncate px-2 py-2 border-0 border-t border-b border-r font-mono text-sm my-auto rounded-r border-gray-400 dark:border-bluegray-500"
styleQr =
"max-w-min dark:bg-bluegray-400 bg-gray-50 mx-auto md:mx-0"
in in
div div
[] []
@ -350,7 +347,7 @@ viewLinks2 texts flags _ source =
, div [ class "py-2" ] , div [ class "py-2" ]
[ div [ div
[ class S.border [ class S.border
, class styleQr , class S.qrCode
] ]
[ qrCodeView texts appUrl [ qrCodeView texts appUrl
] ]
@ -386,7 +383,7 @@ viewLinks2 texts flags _ source =
, div [ class "py-2" ] , div [ class "py-2" ]
[ div [ div
[ class S.border [ class S.border
, class styleQr , class S.qrCode
] ]
[ qrCodeView texts apiUrl [ qrCodeView texts apiUrl
] ]

View File

@ -6,9 +6,7 @@
module Data.Icons exposing module Data.Icons exposing
( addFiles ( addFiles2
, addFiles2
, addFilesIcon
, addFilesIcon2 , addFilesIcon2
, concerned , concerned
, concerned2 , concerned2
@ -60,6 +58,8 @@ module Data.Icons exposing
, personIcon2 , personIcon2
, search , search
, searchIcon , searchIcon
, showQr
, showQrIcon
, source , source
, source2 , source2
, sourceIcon , sourceIcon
@ -321,26 +321,26 @@ editNotesIcon =
i [ class editNotes ] [] i [ class editNotes ] []
addFiles : String
addFiles =
"file plus icon"
addFiles2 : String addFiles2 : String
addFiles2 = addFiles2 =
"fa fa-file-upload" "fa fa-file-upload"
addFilesIcon : Html msg
addFilesIcon =
i [ class addFiles ] []
addFilesIcon2 : String -> Html msg addFilesIcon2 : String -> Html msg
addFilesIcon2 classes = addFilesIcon2 classes =
i [ class addFiles2, class classes ] [] i [ class addFiles2, class classes ] []
showQr : String
showQr =
"fa fa-qrcode"
showQrIcon : String -> Html msg
showQrIcon classes =
i [ class showQr, class classes ] []
tag : String tag : String
tag = tag =
"tag icon" "tag icon"

View File

@ -55,6 +55,8 @@ type alias Texts =
, sendingMailNow : String , sendingMailNow : String
, formatDateTime : Int -> String , formatDateTime : Int -> String
, mailSendSuccessful : String , mailSendSuccessful : String
, showQrCode : String
, close : String
} }
@ -89,6 +91,8 @@ gb =
, sendingMailNow = "Sending e-mail" , sendingMailNow = "Sending e-mail"
, formatDateTime = DF.formatDateTimeLong Messages.UiLanguage.English , formatDateTime = DF.formatDateTimeLong Messages.UiLanguage.English
, mailSendSuccessful = "Mail sent." , mailSendSuccessful = "Mail sent."
, showQrCode = "Show the URL to this page as QR code"
, close = "Close"
} }
@ -123,4 +127,6 @@ de =
, sendingMailNow = "E-Mail wird gesendet" , sendingMailNow = "E-Mail wird gesendet"
, formatDateTime = DF.formatDateTimeLong Messages.UiLanguage.German , formatDateTime = DF.formatDateTimeLong Messages.UiLanguage.German
, mailSendSuccessful = "E-Mail wurde versendet." , mailSendSuccessful = "E-Mail wurde versendet."
, showQrCode = "Den Link zu dieser Seite als QR code anzeigen"
, close = "Schließen"
} }

View File

@ -31,6 +31,7 @@ type alias Texts =
, selectModeTitle : String , selectModeTitle : String
, exitSelectMode : String , exitSelectMode : String
, deleteAttachments : String , deleteAttachments : String
, showQrCode : String
} }
@ -51,6 +52,7 @@ gb =
, selectModeTitle = "Select Mode" , selectModeTitle = "Select Mode"
, exitSelectMode = "Exit Select Mode" , exitSelectMode = "Exit Select Mode"
, deleteAttachments = "Delete attachments" , deleteAttachments = "Delete attachments"
, showQrCode = "Show URL as QR code"
} }
@ -71,4 +73,5 @@ de =
, selectModeTitle = "Auswahlmodus" , selectModeTitle = "Auswahlmodus"
, exitSelectMode = "Auswahlmodus beenden" , exitSelectMode = "Auswahlmodus beenden"
, deleteAttachments = "Anhänge löschen" , deleteAttachments = "Anhänge löschen"
, showQrCode = "Link als QR Code anzeigen"
} }

View File

@ -61,11 +61,11 @@ viewSidebar texts visible flags settings model =
viewContent : Texts -> ItemNav -> Flags -> UiSettings -> Model -> Html Msg viewContent : Texts -> ItemNav -> Flags -> UiSettings -> Model -> Html Msg
viewContent texts inav _ settings model = viewContent texts inav flags settings model =
div div
[ id "content" [ id "content"
, class S.content , class S.content
] ]
[ Html.map ItemDetailMsg [ Html.map ItemDetailMsg
(Comp.ItemDetail.view2 texts.itemDetail inav settings model.detail) (Comp.ItemDetail.view2 texts.itemDetail flags inav settings model.detail)
] ]

View File

@ -8,6 +8,7 @@
port module Ports exposing port module Ports exposing
( checkSearchQueryString ( checkSearchQueryString
, initClipboard , initClipboard
, printElement
, receiveCheckQueryResult , receiveCheckQueryResult
, receiveUiSettings , receiveUiSettings
, removeAccount , removeAccount
@ -48,6 +49,12 @@ port receiveUiSettings : (StoredUiSettings -> msg) -> Sub msg
port requestUiSettings : AuthResult -> Cmd msg port requestUiSettings : AuthResult -> Cmd msg
{-| Creates a new window/tab, writes the contents of the given element
and calls the print dialog.
-}
port printElement : String -> Cmd msg
setUiTheme : UiTheme -> Cmd msg setUiTheme : UiTheme -> Cmd msg
setUiTheme theme = setUiTheme theme =
internalSetUiTheme (Data.UiTheme.toString theme) internalSetUiTheme (Data.UiTheme.toString theme)

View File

@ -351,3 +351,8 @@ tableMain =
tableRow : String tableRow : String
tableRow = tableRow =
"border-t dark:border-bluegray-600" "border-t dark:border-bluegray-600"
qrCode : String
qrCode =
"max-w-min dark:bg-bluegray-400 bg-gray-50 mx-auto md:mx-0"

View File

@ -105,3 +105,31 @@ elmApp.ports.checkSearchQueryString.subscribe(function(args) {
elmApp.ports.receiveCheckQueryResult.send(answer); elmApp.ports.receiveCheckQueryResult.send(answer);
} }
}); });
elmApp.ports.printElement.subscribe(function(id) {
if (id) {
var el = document.getElementById(id);
var head = document.getElementsByTagName('head');
if (head && head.length > 0) {
head = head[0];
}
if (el) {
var w = window.open();
w.document.write('<html>');
if (head) {
w.document.write('<head>');
['title', 'meta'].forEach(function(el) {
var headEls = head.getElementsByTagName(el);
for (var i=0; i<headEls.length; i++) {
w.document.write(headEls.item(i).outerHTML);
}
});
w.document.write('</head>');
}
w.document.write('<body>');
w.document.write(el.outerHTML);
w.document.write('<script type="application/javascript">window.print(); window.close();</script>');
w.document.write('</body></html>');
}
}
});