1module UI.Interface.State exposing (..)
2
3import Alfred
4import Debouncer.Basic as Debouncer
5import Maybe.Extra as Maybe
6import Notifications
7import Return exposing (return)
8import Return.Ext as Return
9import Theme
10import Tracks
11import UI.Alfred.State as Alfred
12import UI.Common.State as Common
13import UI.Common.Types exposing (DebounceManager)
14import UI.DnD as DnD
15import UI.Page as Page
16import UI.Playlists.State as Playlists
17import UI.Ports as Ports
18import UI.Queue.State as Queue
19import UI.Theme
20import UI.Types exposing (..)
21import UI.User.State.Export exposing (saveEnclosedUserData)
22
23
24
25-- 🔱
26
27
28assistWithChangingTheme : Manager
29assistWithChangingTheme model =
30 { action =
31 \{ result } ->
32 case result of
33 Just { value } ->
34 value
35 |> Alfred.command
36 |> Maybe.map List.singleton
37 |> Maybe.withDefault []
38
39 Nothing ->
40 []
41 , index =
42 [ { name = Just "Themes"
43 , items =
44 List.map
45 (\theme ->
46 { icon = Just (theme.icon 16)
47 , title = theme.title
48 , value = Alfred.Command (ChangeTheme { id = theme.id })
49 }
50 )
51 UI.Theme.list
52 }
53 ]
54 , message = "Choose a theme."
55 , operation = Alfred.Query
56 }
57 |> Alfred.create
58 |> (\a -> Alfred.assign a model)
59
60
61blur : Manager
62blur model =
63 Return.singleton { model | focusedOnInput = False, pressedKeys = [] }
64
65
66changeTheme : Theme.Id -> Manager
67changeTheme id model =
68 saveEnclosedUserData { model | theme = Just id }
69
70
71contextMenuConfirmation : String -> Msg -> Manager
72contextMenuConfirmation conf msg model =
73 return
74 { model | confirmation = Just conf }
75 (Return.task msg)
76
77
78copyToClipboard : String -> Manager
79copyToClipboard string =
80 string
81 |> Ports.copyToClipboard
82 |> Return.communicate
83
84
85resizeDebounce : DebounceManager
86resizeDebounce =
87 Common.debounce
88 .resizeDebouncer
89 (\d m -> { m | resizeDebouncer = d })
90 ResizeDebounce
91
92
93dnd : DnD.Msg Int -> Manager
94dnd dragMsg model =
95 let
96 ( d, { initiated } ) =
97 DnD.update dragMsg model.dnd
98
99 m =
100 if initiated then
101 { model | dnd = d, isDragging = True }
102
103 else
104 { model | dnd = d }
105 in
106 if DnD.hasDropped d then
107 case m.page of
108 Page.Queue _ ->
109 let
110 ( from, to ) =
111 ( Maybe.withDefault 0 <| DnD.modelSubject d
112 , Maybe.withDefault 0 <| DnD.modelTarget d
113 )
114
115 newFuture =
116 Queue.moveItem
117 { from = from, to = to, shuffle = m.shuffle }
118 m.playingNext
119 in
120 Queue.fill { m | playingNext = newFuture }
121
122 Page.Index ->
123 let
124 trackCanBeMoved =
125 not m.favouritesOnly && Maybe.isNothing m.searchTerm
126 in
127 case m.scene of
128 Tracks.Covers ->
129 -- TODO
130 Return.singleton m
131
132 Tracks.List ->
133 if trackCanBeMoved then
134 Playlists.moveTrackInSelected
135 { to = Maybe.withDefault 0 (DnD.modelTarget d) }
136 m
137
138 else
139 "Can't move tracks in a playlist whilst using favourites-only mode, or while searching."
140 |> Notifications.casual
141 |> Common.showNotificationWithModel m
142
143 _ ->
144 Return.singleton m
145
146 else
147 Return.singleton m
148
149
150focusedOnInput : Manager
151focusedOnInput model =
152 Return.singleton { model | focusedOnInput = True }
153
154
155hideOverlay : Manager
156hideOverlay model =
157 if Maybe.isJust model.contextMenu then
158 Return.singleton { model | contextMenu = Nothing }
159
160 else if Maybe.isJust model.confirmation then
161 Return.singleton { model | confirmation = Nothing }
162
163 else if Maybe.isJust model.alfred then
164 Return.singleton { model | alfred = Nothing }
165
166 else
167 Return.singleton model
168
169
170lostWindowFocus : Manager
171lostWindowFocus model =
172 Return.singleton { model | focusedOnInput = False, pressedKeys = [] }
173
174
175preferredColorSchemaChanged : { dark : Bool } -> Manager
176preferredColorSchemaChanged { dark } model =
177 Return.singleton { model | darkMode = dark }
178
179
180msgViaContextMenu : Msg -> Manager
181msgViaContextMenu msg model =
182 return
183 (case msg of
184 ContextMenuConfirmation _ _ ->
185 model
186
187 _ ->
188 { model | confirmation = Nothing, contextMenu = Nothing }
189 )
190 (Return.task msg)
191
192
193removeNotification : { id : Int } -> Manager
194removeNotification { id } model =
195 model.notifications
196 |> List.filter (Notifications.id >> (/=) id)
197 |> (\n -> { model | notifications = n })
198 |> Return.singleton
199
200
201removeQueueSelection : Manager
202removeQueueSelection model =
203 Return.singleton { model | selectedQueueItem = Nothing }
204
205
206removeTrackSelection : Manager
207removeTrackSelection model =
208 Return.singleton { model | selectedTrackIndexes = [] }
209
210
211resizedWindow : ( Int, Int ) -> Manager
212resizedWindow ( width, height ) model =
213 Return.singleton
214 { model
215 | contextMenu = Nothing
216 , viewport = { height = toFloat height, width = toFloat width }
217 }
218
219
220searchDebounce : DebounceManager
221searchDebounce =
222 Common.debounce
223 .searchDebouncer
224 (\d m -> { m | searchDebouncer = d })
225 SearchDebounce
226
227
228setIsTouchDevice : Bool -> Manager
229setIsTouchDevice bool model =
230 Return.singleton { model | isTouchDevice = bool }
231
232
233stoppedDragging : Manager
234stoppedDragging model =
235 let
236 notDragging =
237 { model | isDragging = False }
238 in
239 -- Depending on where we stopped dragging something,
240 -- do the appropriate thing.
241 case model.page of
242 Page.Queue _ ->
243 dnd DnD.stoppedDragging notDragging
244
245 Page.Index ->
246 dnd DnD.stoppedDragging notDragging
247
248 _ ->
249 Return.singleton notDragging
250
251
252
253-- MESSAGES
254
255
256onResize : Int -> Int -> Msg
257onResize w h =
258 ( w, h )
259 |> ResizedWindow
260 |> Debouncer.provideInput
261 |> ResizeDebounce