Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor GObject type classes #14

Merged
merged 3 commits into from
Feb 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 BindProp ∷ Type → 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
, name ∷ String
-- name of the player like Spotify or Mozilla Firefox
, identity ∷ String
-- .desktop entry without the extension
, entry ∷ String
, trackid ∷ String
, "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
, volume ∷ Number
, length ∷ Number
, position ∷ Number
)

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 =
( position ∷ EffectFn2 Player Number Unit
, closed ∷ EffectFn1 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 =
( dismissed ∷ EffectFn1 Notification Unit
, closed ∷ EffectFn1 Notification Unit
, invoked ∷ EffectFn2 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 =
( changed ∷ EffectFn1 (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 VariableProps ∷ Type → Row Type
type VariableProps a =
( value ∷ a
)

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
Loading