packages feed

calamity-0.8.0.0: Calamity/Types/Model/Presence/Activity.hs

{-# LANGUAGE TemplateHaskell #-}

-- | User activities
module Calamity.Types.Model.Presence.Activity (
  Activity (..),
  activity,
  ActivityType (..),
  ActivityTimestamps (..),
  ActivityParty (..),
  ActivityAssets (..),
  ActivitySecrets (..),
) where

import Calamity.Internal.UnixTimestamp
import Calamity.Internal.Utils
import Calamity.Types.Snowflake
import Data.Aeson ((.:), (.:?))
import Data.Aeson qualified as Aeson
import Data.Scientific
import Data.Text (Text)
import Data.Time (UTCTime)
import Data.Word
import Optics.TH
import TextShow qualified
import TextShow.TH

data ActivityType
  = Game
  | Streaming
  | Listening
  | Custom
  | Other Int
  deriving (Eq, Show)

instance Aeson.ToJSON ActivityType where
  toJSON Game = Aeson.Number 0
  toJSON Streaming = Aeson.Number 1
  toJSON Listening = Aeson.Number 2
  toJSON Custom = Aeson.Number 4
  toJSON (Other n) = Aeson.Number $ fromIntegral n

instance Aeson.FromJSON ActivityType where
  parseJSON = Aeson.withScientific "ActivityType" $ \n -> case toBoundedInteger @Int n of
    Just v -> case v of
      0 -> pure Game
      1 -> pure Streaming
      2 -> pure Listening
      4 -> pure Custom
      n -> pure $ Other n
    Nothing -> fail $ "Invalid ActivityType: " <> show n

data Activity = Activity
  { name :: Text
  , type_ :: ActivityType
  , url :: Maybe Text
  , timestamps :: Maybe ActivityTimestamps
  , applicationID :: Maybe (Snowflake ())
  , details :: Maybe Text
  , state :: Maybe Text
  , party :: Maybe ActivityParty
  , assets :: Maybe ActivityAssets
  , secrets :: Maybe ActivitySecrets
  , instance_ :: Maybe Bool
  , flags :: Maybe Word64
  }
  deriving (Eq, Show)
  deriving (Aeson.ToJSON) via CalamityToJSON Activity

instance CalamityToJSON' Activity where
  toPairs Activity {..} =
    [ "name" .= name
    , "type" .= type_
    , "url" .?= url
    , "timestamps" .?= timestamps
    , "application_id" .?= applicationID
    , "details" .?= details
    , "state" .?= state
    , "party" .?= party
    , "assets" .?= assets
    , "secrets" .?= secrets
    , "instance" .?= instance_
    , "flags" .?= flags
    ]

instance Aeson.FromJSON Activity where
  parseJSON = Aeson.withObject "Activity" $ \v ->
    Activity
      <$> v .: "name"
      <*> v .: "type"
      <*> v .:? "url"
      <*> v .:? "timestamps"
      <*> v .:? "application_id"
      <*> v .:? "details"
      <*> v .:? "state"
      <*> v .:? "party"
      <*> v .:? "assets"
      <*> v .:? "secrets"
      <*> v .:? "instance"
      <*> v .:? "flags"

-- | Make an 'Activity' with all optional fields set to Nothing
activity :: Text -> ActivityType -> Activity
activity !name !type_ =
  Activity
    { name = name
    , type_ = type_
    , url = Nothing
    , timestamps = Nothing
    , applicationID = Nothing
    , details = Nothing
    , state = Nothing
    , party = Nothing
    , assets = Nothing
    , secrets = Nothing
    , instance_ = Nothing
    , flags = Nothing
    }

data ActivityTimestamps = ActivityTimestamps
  { start :: Maybe UTCTime
  , end :: Maybe UTCTime
  }
  deriving (Eq, Show)
  deriving (TextShow.TextShow) via TextShow.FromStringShow ActivityTimestamps
  deriving (Aeson.ToJSON) via CalamityToJSON ActivityTimestamps

instance CalamityToJSON' ActivityTimestamps where
  toPairs ActivityTimestamps {..} =
    [ "start" .?= fmap UnixTimestamp start
    , "end" .?= fmap UnixTimestamp end
    ]

instance Aeson.FromJSON ActivityTimestamps where
  parseJSON = Aeson.withObject "ActivityTimestamps" $ \v ->
    ActivityTimestamps
      <$> (fmap unUnixTimestamp <$> v .:? "start")
      <*> (fmap unUnixTimestamp <$> v .:? "end")

data ActivityParty = ActivityParty
  { id :: Maybe Text
  , size :: Maybe (Int, Int)
  }
  deriving (Eq, Show)
  deriving (Aeson.ToJSON) via CalamityToJSON ActivityParty

instance CalamityToJSON' ActivityParty where
  toPairs ActivityParty {..} =
    [ "id" .?= id
    , "size" .?= size
    ]

instance Aeson.FromJSON ActivityParty where
  parseJSON = Aeson.withObject "ActivityParty" $ \v ->
    ActivityParty
      <$> v .:? "id"
      <*> v .:? "size"

data ActivityAssets = ActivityAssets
  { largeImage :: Maybe Text
  , largeText :: Maybe Text
  , smallImage :: Maybe Text
  , smallText :: Maybe Text
  }
  deriving (Eq, Show)
  deriving (Aeson.ToJSON) via CalamityToJSON ActivityAssets

instance CalamityToJSON' ActivityAssets where
  toPairs ActivityAssets {..} =
    [ "large_image" .?= largeImage
    , "large_text" .?= largeText
    , "small_image" .?= smallImage
    , "small_text" .?= smallText
    ]

instance Aeson.FromJSON ActivityAssets where
  parseJSON = Aeson.withObject "ActivityAssets" $ \v ->
    ActivityAssets
      <$> v .:? "large_image"
      <*> v .:? "large_text"
      <*> v .:? "small_image"
      <*> v .:? "small_text"

data ActivitySecrets = ActivitySecrets
  { join :: Maybe Text
  , spectate :: Maybe Text
  , match :: Maybe Text
  }
  deriving (Eq, Show)
  deriving (Aeson.ToJSON) via CalamityToJSON ActivitySecrets

instance CalamityToJSON' ActivitySecrets where
  toPairs ActivitySecrets {..} =
    [ "join" .?= join
    , "spectate" .?= spectate
    , "match" .?= match
    ]

instance Aeson.FromJSON ActivitySecrets where
  parseJSON = Aeson.withObject "ActivitySecrets" $ \v ->
    ActivitySecrets
      <$> v .:? "join"
      <*> v .:? "spectate"
      <*> v .:? "match"

$(deriveTextShow ''ActivityType)
$(deriveTextShow ''ActivityParty)
$(deriveTextShow ''ActivityAssets)
$(deriveTextShow ''ActivitySecrets)
$(deriveTextShow ''Activity)
$(makeFieldLabelsNoPrefix ''Activity)
$(makeFieldLabelsNoPrefix ''ActivityTimestamps)
$(makeFieldLabelsNoPrefix ''ActivityParty)
$(makeFieldLabelsNoPrefix ''ActivityAssets)
$(makeFieldLabelsNoPrefix ''ActivitySecrets)