Skip to content

Commit

Permalink
Refactor GObject type classes (#14)
Browse files Browse the repository at this point in the history
* Refactor `GObjectSignal` type class

Now the instances will only map the object to a row type of callbacks.

* Refactor `BindProp` type class

* Fix missing export
  • Loading branch information
postsolar authored Feb 24, 2024
1 parent 535c3bb commit f2de856
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 182 deletions.
2 changes: 1 addition & 1 deletion src/AGS/Binding.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const unsafeBindPropImpl =
export const unsafeBindProp =
prop => object =>
object.bind(prop)

Expand Down
19 changes: 12 additions & 7 deletions src/AGS/Binding.purs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ module AGS.Binding
( Binding
, class BindProp
, bindProp
, unsafeBindProp
, ValueOrBinding
, overValue
, overBinding
Expand All @@ -14,6 +13,7 @@ import Prelude
import Control.Apply (lift2)
import Data.Either (either)
import Data.Symbol (class IsSymbol, reflectSymbol)
import Prim.Row as R
import Type.Proxy (Proxy(..))
import Untagged.TypeCheck (class HasRuntimeType)
import Untagged.Union (OneOf, asOneOf, toEither1)
Expand Down Expand Up @@ -56,14 +56,19 @@ foreign import applyBinding ∷ ∀ a b. Binding (a → b) → Binding a → Bin
foreign import pureBinding a. a Binding a
foreign import bindBinding a b. Binding a (a Binding b) Binding b

class BindProp k. Type k Type Constraint
class BindProp o p t | o p t where
bindProp o Binding t
class BindPropType Row Type Constraint
class BindProp object props | object props

unsafeBindProp @p @o @t. IsSymbol p BindProp o p t o Binding t
unsafeBindProp = unsafeBindPropImpl (reflectSymbol (Proxy @p))
bindProp
@prop @obj ty props rt
. R.Cons prop ty rt props
IsSymbol prop
BindProp obj props
obj
Binding ty
bindProp = unsafeBindProp (reflectSymbol (Proxy @prop))

foreign import unsafeBindPropImpl o t. String o Binding t
foreign import unsafeBindProp o t. String o Binding t

-- * ValueOrBinding

Expand Down
113 changes: 39 additions & 74 deletions src/AGS/Service/Mpris.purs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ module AGS.Service.Mpris
, matchPlayer
, BusName
, Player
, PlayerProps
, PlayerSignals
, PlayerRecord
, PlayerRecordR
, MprisMetadata
Expand All @@ -23,19 +25,14 @@ module AGS.Service.Mpris

import Prelude

import AGS.Binding (class BindProp, Binding, unsafeBindProp)
import AGS.Binding (class BindProp, Binding)
import AGS.Service (class BindServiceProp, class ServiceConnect, Service)
import Data.Maybe (Maybe)
import Data.Nullable (Nullable, toMaybe)
import Data.Symbol (class IsSymbol, reflectSymbol)
import Effect (Effect)
import Effect.Uncurried (EffectFn1, EffectFn2)
import GObject
( class GObjectSignal
, HandlerID
, unsafeConnect
, unsafeCopyGObjectProps
)
import GObject (class GObjectSignal, HandlerID, unsafeCopyGObjectProps)
import Record as R
import Record.Studio.MapKind (mapRecordKind)
import Type.Proxy (Proxy(..))
Expand Down Expand Up @@ -157,78 +154,46 @@ fromPlayer = unsafeCopyGObjectProps @PlayerRecordR
fromForeignMetadata MprisMetadataF UndefinedOr MprisMetadata
fromForeignMetadata = mapRecordKind uorToMaybe

-- the dbus name that starts with org.mpris.MediaPlayer2
instance BindProp Player "bus-name" String where
bindProp o = unsafeBindProp @"bus-name" o

-- stripped from busName like spotify or firefox
instance BindProp Player "name" String where
bindProp o = unsafeBindProp @"name" o

-- name of the player like Spotify or Mozilla Firefox
instance BindProp Player "identity" String where
bindProp o = unsafeBindProp @"identity" o

-- .desktop entry without the extension
instance BindProp Player "entry" String where
bindProp o = unsafeBindProp @"entry" o

instance BindProp Player "trackid" String where
bindProp o = unsafeBindProp @"trackid" o

instance BindProp Player "track-artists" (Array String) where
bindProp o = unsafeBindProp @"track-artists" o

instance BindProp Player "track-album" String where
bindProp o = unsafeBindProp @"track-album" o

instance BindProp Player "track-title" String where
bindProp o = unsafeBindProp @"track-title" o

instance BindProp Player "track-cover-url" String where
bindProp o = unsafeBindProp @"track-cover-url" o

-- path to the cached cover art
instance BindProp Player "cover-path" String where
bindProp o = unsafeBindProp @"cover-path" o

-- "Playing" | "Paused" | "Stopped"
instance BindProp Player "play-back-status" String where
bindProp o = unsafeBindProp @"play-back-status" o

instance BindProp Player "can-go-next" Boolean where
bindProp o = unsafeBindProp @"can-go-next" o

instance BindProp Player "can-go-prev" Boolean where
bindProp o = unsafeBindProp @"can-go-prev" o

instance BindProp Player "can-play" Boolean where
bindProp o = unsafeBindProp @"can-play" o

-- null if shuffle is unsupported by the player
instance BindProp Player "shuffle-status" (Nullable Boolean) where
bindProp o = unsafeBindProp @"shuffle-status" o

-- "None" | "Track" | "Playlist" | null if shuffle is unsupported by the player
instance BindProp Player "loop-status" (Nullable String) where
bindProp o = unsafeBindProp @"loop-status" o

instance BindProp Player "volume" Number where
bindProp o = unsafeBindProp @"volume" o

instance BindProp Player "length" Number where
bindProp o = unsafeBindProp @"length" o
type PlayerProps =
-- the dbus name that starts with org.mpris.MediaPlayer2
( "bus-name" ∷ String
-- stripped from busName like spotify or firefox
, nameString
-- name of the player like Spotify or Mozilla Firefox
, identityString
-- .desktop entry without the extension
, entryString
, trackidString
, "track-artists" ∷ Array String
, "track-album" ∷ String
, "track-title" ∷ String
, "track-cover-url" ∷ String
-- path to the cached cover art
, "cover-path" ∷ String
-- "Playing" | "Paused" | "Stopped"
, "play-back-status" ∷ String
, "can-go-next" ∷ Boolean
, "can-go-prev" ∷ Boolean
, "can-play" ∷ Boolean
-- null if shuffle is unsupported by the player
, "shuffle-status" ∷ Nullable Boolean
-- "None" | "Track" | "Playlist" | null if shuffle is unsupported by the player
, "loop-status" ∷ Nullable String
, volumeNumber
, lengthNumber
, positionNumber
)

instance BindProp Player "position" Number where
bindProp o = unsafeBindProp @"position" o
instance BindProp Player PlayerProps

-- * Signals

instance GObjectSignal "position" Player (EffectFn2 Player Number Unit) where
connect cb player = unsafeConnect @"position" cb player
type PlayerSignals =
( positionEffectFn2 Player Number Unit
, closedEffectFn1 Player Unit
)

instance GObjectSignal "closed" Player (EffectFn1 Player Unit) where
connect cb player = unsafeConnect @"closed" cb player
instance GObjectSignal Player PlayerSignals

-- * Methods

Expand Down
26 changes: 9 additions & 17 deletions src/AGS/Service/Notifications.purs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module AGS.Service.Notifications
( Notifications
, NotificationsSignals
, Notification
, NotificationSignals
, NotificationID(..)
, NotificationsOptions
, NotificationRecord
Expand Down Expand Up @@ -43,12 +44,7 @@ import Data.Time.Duration (Milliseconds(..))
import Effect (Effect)
import Effect.Aff.Compat (runEffectFn1)
import Effect.Uncurried (EffectFn2)
import GObject
( class GObjectSignal
, HandlerID
, unsafeConnect
, unsafeCopyGObjectProps
)
import GObject (class GObjectSignal, HandlerID, unsafeCopyGObjectProps)
import Partial.Unsafe (unsafePartial)
import Record as Record
import Record.Studio as RS
Expand Down Expand Up @@ -105,9 +101,7 @@ getOptions ∷ Effect { | NotificationsOptions }
getOptions = getOptionsImpl (RS.keys (Proxy @NotificationsOptions))

setOptions
( { | NotificationsOptions }
{ | NotificationsOptions }
)
({ | NotificationsOptions } { | NotificationsOptions })
Effect Unit
setOptions f = setOptionsImpl <<< f =<< getOptions

Expand Down Expand Up @@ -149,15 +143,13 @@ fromNotification =

-- * Signals

instance GObjectSignal "dismissed" Notification (EffectFn1 Notification Unit) where
connect cb notification = unsafeConnect @"dismissed" cb notification

instance GObjectSignal "closed" Notification (EffectFn1 Notification Unit) where
connect cb notification = unsafeConnect @"closed" cb notification
type NotificationSignals =
( dismissedEffectFn1 Notification Unit
, closedEffectFn1 Notification Unit
, invokedEffectFn2 Notification ActionID Unit
)

instance
GObjectSignal "invoked" Notification (EffectFn2 Notification ActionID Unit) where
connect cb notification = unsafeConnect @"invoked" cb notification
instance GObjectSignal Notification NotificationSignals

-- * Bindings and props

Expand Down
4 changes: 0 additions & 4 deletions src/AGS/Variable.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ export const set =
f => v => () =>
v.setValue(f(v.value))

export const bindValue =
v =>
v.bind("value")

export const store =
v =>
Variable(v)
Expand Down
27 changes: 20 additions & 7 deletions src/AGS/Variable.purs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module AGS.Variable
( Variable
, VariableSignals
, get
, set
, bindValue
Expand All @@ -11,24 +12,36 @@ module AGS.Variable

import Prelude

import AGS.Binding (Binding)
import AGS.Binding (class BindProp, Binding, bindProp)
import Data.Time.Duration (Milliseconds)
import Effect (Effect)
import Effect.Uncurried (EffectFn1)
import GObject (class GObjectSignal, unsafeConnect)
import GObject (class GObjectSignal)

foreign import data Variable Type Type

instance GObjectSignal "changed" (Variable a) (EffectFn1 (Variable a) Unit) where
connect callback variable = unsafeConnect @"changed" callback variable
type VariableSignals a =
( changedEffectFn1 (Variable a) Unit
)

instance GObjectSignal (Variable a) (VariableSignals a)

-- | Get the value of a variable.
foreign import get a. Variable a Effect a

-- | Update the value of a variable.
foreign import set a. (a a) Variable a Effect Unit

type VariablePropsType Row Type
type VariableProps a =
( valuea
)

instance BindProp (Variable a) (VariableProps a)

-- | Bind the value of a variable.
foreign import bindValue a. Variable a Binding a
bindValue a. Variable a Binding a
bindValue = bindProp @"value"

-- | Create a variable.
foreign import store a. a Variable a
Expand All @@ -37,7 +50,7 @@ foreign import store ∷ ∀ a. a → Variable a
foreign import poll
a
. { initValue a
, interval Int
, interval Milliseconds
, transform String a
, command Array String
}
Expand All @@ -47,7 +60,7 @@ foreign import poll
foreign import serve
a
. { initValue a
, interval Int
, interval Milliseconds
, command Effect a
}
Effect (Variable a)
Expand Down
2 changes: 1 addition & 1 deletion src/GObject.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const connectImpl =
(signal, handler, object) =>
(signal, object, handler) =>
object.connect(signal, handler)

export const disconnectImpl =
Expand Down
Loading

0 comments on commit f2de856

Please sign in to comment.