packages feed

desktop-portal 0.1.1.0 → 0.2.0.0

raw patch · 8 files changed

+60/−20 lines, 8 filesdep +modern-uriPVP ok

version bump matches the API change (PVP)

Dependencies added: modern-uri

API changes (from Hackage documentation)

- Desktop.Portal.Account: GetUserInformationResults :: Text -> Text -> Maybe Text -> GetUserInformationResults
+ Desktop.Portal.Account: GetUserInformationResults :: Text -> Text -> Maybe FilePath -> GetUserInformationResults
- Desktop.Portal.Account: [$sel:image:GetUserInformationResults] :: GetUserInformationResults -> Maybe Text
+ Desktop.Portal.Account: [$sel:image:GetUserInformationResults] :: GetUserInformationResults -> Maybe FilePath
- Desktop.Portal.FileChooser: OpenFileResults :: [Text] -> Maybe [ChoiceComboSelection] -> Maybe Filter -> OpenFileResults
+ Desktop.Portal.FileChooser: OpenFileResults :: [FilePath] -> Maybe [ChoiceComboSelection] -> Maybe Filter -> OpenFileResults
- Desktop.Portal.FileChooser: SaveFileOptions :: Maybe Text -> Maybe Text -> Maybe Text -> Maybe Bool -> Maybe [Filter] -> Maybe Filter -> Maybe [ChoiceCombo] -> Maybe Text -> Maybe Text -> Maybe Text -> SaveFileOptions
+ Desktop.Portal.FileChooser: SaveFileOptions :: Maybe Text -> Maybe Text -> Maybe Text -> Maybe Bool -> Maybe [Filter] -> Maybe Filter -> Maybe [ChoiceCombo] -> Maybe Text -> Maybe FilePath -> Maybe FilePath -> SaveFileOptions
- Desktop.Portal.FileChooser: SaveFileResults :: [Text] -> Maybe [ChoiceComboSelection] -> Maybe Filter -> SaveFileResults
+ Desktop.Portal.FileChooser: SaveFileResults :: [FilePath] -> Maybe [ChoiceComboSelection] -> Maybe Filter -> SaveFileResults
- Desktop.Portal.FileChooser: [$sel:currentFile:SaveFileOptions] :: SaveFileOptions -> Maybe Text
+ Desktop.Portal.FileChooser: [$sel:currentFile:SaveFileOptions] :: SaveFileOptions -> Maybe FilePath
- Desktop.Portal.FileChooser: [$sel:currentFolder:SaveFileOptions] :: SaveFileOptions -> Maybe Text
+ Desktop.Portal.FileChooser: [$sel:currentFolder:SaveFileOptions] :: SaveFileOptions -> Maybe FilePath
- Desktop.Portal.FileChooser: [$sel:uris:OpenFileResults] :: OpenFileResults -> [Text]
+ Desktop.Portal.FileChooser: [$sel:uris:OpenFileResults] :: OpenFileResults -> [FilePath]
- Desktop.Portal.FileChooser: [$sel:uris:SaveFileResults] :: SaveFileResults -> [Text]
+ Desktop.Portal.FileChooser: [$sel:uris:SaveFileResults] :: SaveFileResults -> [FilePath]

Files

ChangeLog.md view
@@ -1,3 +1,7 @@+## 0.2.0.0+### Changed+- Functions now return FilePath instead of Text, where the value is always a file URI.+ ## 0.1.1.0 ### Added - Add Settings portal support.
README.md view
@@ -25,6 +25,7 @@ - Functions should take records called `...Options` and return records called `...Results`. - `...Options` records should have a `Default` instance where all fields have a reasonable empty value. - Record fields should not have unique prefixes.+- API methods that return URIs that are known to always be `file:` URIs should be wrapped with functions returning [`Prelude.FilePath`](https://hackage.haskell.org/package/base-4.18.0.0/docs/Prelude.html#t:FilePath) (at some point this can be replaced with [`System.OsPath`](https://hackage.haskell.org/package/filepath-1.4.100.3/docs/System-OsPath.html#t:OsPath)). If they are not known to be file URIs, then [`Text.URI.URI`](https://hackage.haskell.org/package/modern-uri-0.3.6.0/docs/Text-URI.html#t:URI) should be returned.  ### To format the source code ```bash
desktop-portal.cabal view
@@ -1,6 +1,6 @@ cabal-version:      1.12 name:               desktop-portal-version:            0.1.1.0+version:            0.2.0.0 license:            MIT license-file:       LICENSE maintainer:         garethdanielsmith@gmail.com@@ -50,6 +50,7 @@         containers <0.7,         data-default-class <0.2,         dbus >=1.2.28 && <1.3,+        modern-uri <0.4,         random <1.3,         text <1.3 @@ -88,6 +89,7 @@         desktop-portal,         hspec >=2 && <3,         hspec-expectations <0.9,+        modern-uri <0.4,         process <1.7,         random <1.3,         text <1.3
src/Desktop/Portal/Account.hs view
@@ -15,7 +15,7 @@ import Data.Maybe (catMaybes, fromMaybe) import Data.Text (Text) import Desktop.Portal.Internal (Client, Request, sendRequest)-import Desktop.Portal.Util (optionalFromVariant, toVariantPair)+import Desktop.Portal.Util (decodeFileUri, mapJust, optionalFromVariant, toVariantPair)  data GetUserInformationOptions = GetUserInformationOptions   { window :: Maybe Text,@@ -33,7 +33,7 @@ data GetUserInformationResults = GetUserInformationResults   { id :: Text,     name :: Text,-    image :: Maybe Text+    image :: Maybe FilePath   }   deriving (Eq, Show) @@ -54,7 +54,7 @@       resMap         | Just id' <- DBus.fromVariant =<< Map.lookup "id" resMap,           Just name <- DBus.fromVariant =<< Map.lookup "name" resMap,-          Just image <- optionalFromVariant "image" resMap ->+          Just image <- mapJust decodeFileUri =<< optionalFromVariant "image" resMap -> do             pure GetUserInformationResults {id = id', name, image}       resMap ->         throwIO . DBus.clientError $ "getUserInformation: could not parse response: " <> show resMap
src/Desktop/Portal/FileChooser.hs view
@@ -26,10 +26,10 @@ import Data.Map (Map) import Data.Map.Strict qualified as Map import Data.Maybe (catMaybes, fromMaybe)-import Data.Text (Text)+import Data.Text (Text, pack) import Data.Word (Word32) import Desktop.Portal.Internal (Client, Request, sendRequest)-import Desktop.Portal.Util (encodeNullTerminatedUtf8, mapJust, optionalFromVariant, toVariantPair, toVariantPair')+import Desktop.Portal.Util (decodeFileUris, encodeNullTerminatedUtf8, mapJust, optionalFromVariant, toVariantPair, toVariantPair')  data Filter = Filter   { name :: Text,@@ -90,7 +90,7 @@       }  data OpenFileResults = OpenFileResults-  { uris :: [Text],+  { uris :: [FilePath],     choices :: Maybe [ChoiceComboSelection],     currentFilter :: Maybe Filter   }@@ -105,8 +105,8 @@     currentFilter :: Maybe Filter,     choices :: Maybe [ChoiceCombo],     currentName :: Maybe Text,-    currentFolder :: Maybe Text,-    currentFile :: Maybe Text+    currentFolder :: Maybe FilePath,+    currentFile :: Maybe FilePath   }   deriving (Eq, Show) @@ -126,7 +126,7 @@       }  data SaveFileResults = SaveFileResults-  { uris :: [Text],+  { uris :: [FilePath],     choices :: Maybe [ChoiceComboSelection],     currentFilter :: Maybe Filter   }@@ -168,8 +168,8 @@           toVariantPair' encodeFilter "current_filter" options.currentFilter,           toVariantPair' (fmap encodeCombo) "choices" options.choices,           toVariantPair "current_name" options.currentName,-          toVariantPair "current_folder" (encodeNullTerminatedUtf8 <$> options.currentFolder),-          toVariantPair "current_file" (encodeNullTerminatedUtf8 <$> options.currentFile)+          toVariantPair "current_folder" (encodeNullTerminatedUtf8 . pack <$> options.currentFolder),+          toVariantPair "current_file" (encodeNullTerminatedUtf8 . pack <$> options.currentFile)         ]      parseResponse resMap = do@@ -179,7 +179,7 @@ parseOpenFileResponse :: Map Text Variant -> IO OpenFileResults parseOpenFileResponse = \case   resMap-    | Just uris <- DBus.fromVariant =<< Map.lookup "uris" resMap,+    | Just uris <- decodeFileUris =<< DBus.fromVariant =<< Map.lookup "uris" resMap,       Just choicesRaw <- optionalFromVariant "choices" resMap,       choices <- fmap decodeChoiceComboSelection <$> choicesRaw,       Just currentFilterRaw <- optionalFromVariant "current_filter" resMap,
src/Desktop/Portal/Util.hs view
@@ -1,9 +1,13 @@+{-# LANGUAGE ViewPatterns #-}+ module Desktop.Portal.Util   ( optionalFromVariant,     mapJust,     toVariantPair,     toVariantPair',     encodeNullTerminatedUtf8,+    decodeFileUri,+    decodeFileUris,   ) where @@ -13,8 +17,10 @@ import Data.ByteString.Lazy (ByteString) import Data.Map (Map) import Data.Map qualified as Map-import Data.Text (Text)+import Data.Text (Text, unpack) import Data.Text.Encoding qualified as Encoding+import Text.URI (Authority (..), URI (..))+import Text.URI qualified as URI  -- | Returns @Just Nothing@ if the field does not exist, @Just (Just x)@ if it does exist and -- can be turned into the expected type, or @Nothing@ if the field exists with the wrong type.@@ -38,3 +44,30 @@ encodeNullTerminatedUtf8 :: Text -> ByteString encodeNullTerminatedUtf8 txt =   Binary.toLazyByteString (Encoding.encodeUtf8Builder txt <> Binary.singleton 0)++decodeFileUri :: Text -> Maybe FilePath+decodeFileUri uri =+  case URI.mkURI uri of+    Just+      URI+        { uriScheme = Just (URI.unRText -> "file"),+          uriAuthority = (validAuthority -> True),+          uriPath = Just (_trailingSlash, parts),+          uriQuery = [],+          uriFragment = Nothing+        } -> Just . unpack $ foldMap (("/" <>) . URI.unRText) parts+    _ ->+      Nothing+  where+    validAuthority = \case+      Left True -> True+      Right+        Authority+          { authUserInfo = Nothing,+            authHost = (URI.unRText -> ""),+            authPort = Nothing+          } -> True+      _ -> False++decodeFileUris :: [Text] -> Maybe [FilePath]+decodeFileUris = traverse decodeFileUri
test/Desktop/Portal/AccountSpec.hs view
@@ -36,11 +36,11 @@               successResponse                 [ ("id", toVariantText "_id"),                   ("name", toVariantText "_name"),-                  ("image", toVariantText "_img")+                  ("image", toVariantText "file:///some/path")                 ]         withRequestResponse handle accountInterface "GetUserInformation" responseBody $ do           (Portal.getUserInformation (client handle) def >>= Portal.await)-            `shouldReturn` Just (GetUserInformationResults "_id" "_name" (Just "_img"))+            `shouldReturn` Just (GetUserInformationResults "_id" "_name" (Just "/some/path"))        it "should decode response without image" $ \handle -> do         let responseBody =
test/Desktop/Portal/FileChooserSpec.hs view
@@ -103,7 +103,7 @@         withRequestResponse handle fileChooserInterface "OpenFile" responseBody $ do           (Portal.openFile (client handle) def >>= Portal.await)             `shouldReturn` Just-              (OpenFileResults {uris = ["file:///a/b/c"], choices = Nothing, currentFilter = Nothing})+              (OpenFileResults {uris = ["/a/b/c"], choices = Nothing, currentFilter = Nothing})        it "should decode response with all Justs" $ \handle -> do         let responseBody =@@ -116,7 +116,7 @@           (Portal.openFile (client handle) def >>= Portal.await)             `shouldReturn` Just               ( OpenFileResults-                  { uris = ["file:///a/b/c"],+                  { uris = ["/a/b/c"],                     choices = Just [ChoiceComboSelection {comboId = "_comboId", optionId = "_optionId"}],                     currentFilter = Just Filter {name = "_filterId", fileTypes = [GlobFilter "*.md"]}                   }@@ -214,7 +214,7 @@         withRequestResponse handle fileChooserInterface "SaveFile" responseBody $ do           (Portal.saveFile (client handle) def >>= Portal.await)             `shouldReturn` Just-              (SaveFileResults {uris = ["file:///a/b/c"], choices = Nothing, currentFilter = Nothing})+              (SaveFileResults {uris = ["/a/b/c"], choices = Nothing, currentFilter = Nothing})        it "should decode response with all Justs" $ \handle -> do         let responseBody =@@ -227,7 +227,7 @@           (Portal.saveFile (client handle) def >>= Portal.await)             `shouldReturn` Just               ( SaveFileResults-                  { uris = ["file:///a/b/c"],+                  { uris = ["/a/b/c"],                     choices = Just [ChoiceComboSelection {comboId = "_comboId", optionId = "_optionId"}],                     currentFilter = Just Filter {name = "_filterId", fileTypes = [GlobFilter "*.md"]}                   }