Changeset View
Changeset View
Standalone View
Standalone View
applets/mediacontroller/contents/ui/ExpandedRepresentation.qml
Show All 32 Lines | 32 | Item { | |||
---|---|---|---|---|---|
33 | id: expandedRepresentation | 33 | id: expandedRepresentation | ||
34 | 34 | | |||
35 | Layout.minimumWidth: units.gridUnit * 15 | 35 | Layout.minimumWidth: units.gridUnit * 15 | ||
36 | Layout.minimumHeight: units.gridUnit * 23 | 36 | Layout.minimumHeight: units.gridUnit * 23 | ||
37 | Layout.preferredWidth: Layout.minimumWidth * 1.5 | 37 | Layout.preferredWidth: Layout.minimumWidth * 1.5 | ||
38 | Layout.preferredHeight: Layout.minimumHeight * 1.5 | 38 | Layout.preferredHeight: Layout.minimumHeight * 1.5 | ||
39 | 39 | | |||
40 | readonly property int controlSize: units.iconSizes.large | 40 | readonly property int controlSize: units.iconSizes.large | ||
41 | | ||||
42 | property double position: mpris2Source.currentData.Position || 0 | | |||
43 | readonly property real rate: mpris2Source.currentData.Rate || 1 | | |||
44 | readonly property double length: currentMetadata ? currentMetadata["mpris:length"] || 0 : 0 | | |||
45 | readonly property bool canSeek: mpris2Source.currentData.CanSeek || false | | |||
46 | readonly property bool softwareRendering: GraphicsInfo.api === GraphicsInfo.Software | 41 | readonly property bool softwareRendering: GraphicsInfo.api === GraphicsInfo.Software | ||
47 | | ||||
48 | // only show hours (the default for KFormat) when track is actually longer than an hour | | |||
49 | readonly property int durationFormattingOptions: length >= 60*60*1000*1000 ? 0 : KCoreAddons.FormatTypes.FoldHours | | |||
50 | | ||||
51 | property bool disablePositionUpdate: false | | |||
52 | property bool keyPressed: false | 42 | property bool keyPressed: false | ||
53 | 43 | | |||
54 | function retrievePosition() { | 44 | // only show hours (the default for KFormat) when track is actually longer than an hour | ||
55 | var service = mpris2Source.serviceForSource(mpris2Source.current); | 45 | readonly property int durationFormattingOptions: Media.length >= 60*60*1000*1000 ? 0 : KCoreAddons.FormatTypes.FoldHours | ||
56 | var operation = service.operationDescription("GetPosition"); | | |||
57 | service.startOperationCall(operation); | | |||
58 | } | | |||
59 | 46 | | |||
60 | Connections { | 47 | Connections { | ||
61 | target: plasmoid | 48 | target: plasmoid | ||
62 | onExpandedChanged: { | 49 | onExpandedChanged: { | ||
63 | if (plasmoid.expanded) { | 50 | if (plasmoid.expanded) { | ||
64 | retrievePosition(); | 51 | Media.retrievePosition() | ||
65 | } | 52 | } | ||
66 | } | 53 | } | ||
67 | } | 54 | } | ||
68 | 55 | | |||
69 | onPositionChanged: { | 56 | Connections { | ||
70 | // we don't want to interrupt the user dragging the slider | 57 | target: Media | ||
58 | function onSongLengthChanged(length) { | ||||
59 | Media.lockPositionUpdate = true | ||||
60 | { | ||||
61 | seekSlider.value = 0 | ||||
62 | seekSlider.to = Media.songLength | ||||
63 | Media.retrievePosition() | ||||
64 | } | ||||
65 | Media.lockPositionUpdate= false | ||||
broulik: Coding style, space | |||||
66 | } | ||||
67 | function onPositionChanged(position) { | ||||
68 | // Don't interrupt an active drag. | ||||
71 | if (!seekSlider.pressed && !keyPressed) { | 69 | if (!seekSlider.pressed && !keyPressed) { | ||
72 | // we also don't want passive position updates | 70 | Media.lockPositionUpdate = true | ||
73 | disablePositionUpdate = true | 71 | { | ||
74 | seekSlider.value = position | 72 | seekSlider.value = Media.position | ||
75 | disablePositionUpdate = false | 73 | } | ||
74 | Media.lockPositionUpdate = false | ||||
76 | } | 75 | } | ||
77 | } | 76 | } | ||
78 | | ||||
79 | onLengthChanged: { | | |||
80 | disablePositionUpdate = true | | |||
81 | // When reducing maximumValue, value is clamped to it, however | | |||
82 | // when increasing it again it gets its old value back. | | |||
83 | // To keep us from seeking to the end of the track when moving | | |||
84 | // to a new track, we'll reset the value to zero and ask for the position again | | |||
85 | seekSlider.value = 0 | | |||
86 | seekSlider.to = length | | |||
87 | retrievePosition() | | |||
88 | disablePositionUpdate = false | | |||
89 | } | 77 | } | ||
90 | 78 | | |||
91 | Keys.onPressed: keyPressed = true | 79 | Keys.onPressed: keyPressed = true | ||
92 | 80 | | |||
93 | Keys.onReleased: { | 81 | Keys.onReleased: { | ||
94 | keyPressed = false | 82 | keyPressed = false | ||
95 | 83 | | |||
96 | if (!event.modifiers) { | 84 | if (!event.modifiers) { | ||
97 | event.accepted = true | 85 | event.accepted = true | ||
98 | 86 | | |||
99 | if (event.key === Qt.Key_Space || event.key === Qt.Key_K) { | 87 | if (event.key === Qt.Key_Space || event.key === Qt.Key_K) { | ||
100 | // K is YouTube's key for "play/pause" :) | 88 | // K is YouTube's key for "play/pause" :) | ||
101 | root.togglePlaying() | 89 | Media.togglePlaying() | ||
102 | } else if (event.key === Qt.Key_P) { | 90 | } else if (event.key === Qt.Key_P) { | ||
103 | root.action_previous() | 91 | Media.perform(Media.previous) | ||
104 | } else if (event.key === Qt.Key_N) { | 92 | } else if (event.key === Qt.Key_N) { | ||
105 | root.action_next() | 93 | Media.perform(Media.next) | ||
106 | } else if (event.key === Qt.Key_S) { | 94 | } else if (event.key === Qt.Key_S) { | ||
107 | root.action_stop() | 95 | Media.perform(Media.stop) | ||
108 | } else if (event.key === Qt.Key_Left || event.key === Qt.Key_J) { // TODO ltr languages | 96 | } else if (event.key === Qt.Key_Left || event.key === Qt.Key_J) { // TODO ltr languages | ||
109 | // seek back 5s | 97 | // seek back 5s | ||
110 | seekSlider.value = Math.max(0, seekSlider.value - 5000000) // microseconds | 98 | seekSlider.value = Math.max(0, seekSlider.value - 5000000) // microseconds | ||
111 | seekSlider.moved(); | 99 | seekSlider.moved() | ||
broulik: Unrelated cleanup | |||||
cblack: a cleanup is unrelated in a cleanup patch? | |||||
112 | } else if (event.key === Qt.Key_Right || event.key === Qt.Key_L) { | 100 | } else if (event.key === Qt.Key_Right || event.key === Qt.Key_L) { | ||
113 | // seek forward 5s | 101 | // seek forward 5s | ||
114 | seekSlider.value = Math.min(seekSlider.to, seekSlider.value + 5000000) | 102 | seekSlider.value = Math.min(seekSlider.to, seekSlider.value + 5000000) | ||
115 | seekSlider.moved(); | 103 | seekSlider.moved() | ||
116 | } else if (event.key === Qt.Key_Home) { | 104 | } else if (event.key === Qt.Key_Home) { | ||
117 | seekSlider.value = 0 | 105 | seekSlider.value = 0 | ||
118 | seekSlider.moved(); | 106 | seekSlider.moved() | ||
119 | } else if (event.key === Qt.Key_End) { | 107 | } else if (event.key === Qt.Key_End) { | ||
120 | seekSlider.value = seekSlider.to | 108 | seekSlider.value = seekSlider.to | ||
121 | seekSlider.moved(); | 109 | seekSlider.moved() | ||
122 | } else if (event.key >= Qt.Key_0 && event.key <= Qt.Key_9) { | 110 | } else if (event.key >= Qt.Key_0 && event.key <= Qt.Key_9) { | ||
123 | // jump to percentage, ie. 0 = beginnign, 1 = 10% of total length etc | 111 | // jump to percentage, ie. 0 = beginnign, 1 = 10% of total length etc | ||
124 | seekSlider.value = seekSlider.to * (event.key - Qt.Key_0) / 10 | 112 | seekSlider.value = seekSlider.to * (event.key - Qt.Key_0) / 10 | ||
125 | seekSlider.moved(); | 113 | seekSlider.moved() | ||
126 | } else { | 114 | } else { | ||
127 | event.accepted = false | 115 | event.accepted = false | ||
128 | } | 116 | } | ||
129 | } | 117 | } | ||
130 | } | 118 | } | ||
131 | 119 | | |||
132 | ColumnLayout { // Main Column Layout | 120 | ColumnLayout { // Main Column Layout | ||
133 | id: mainCol | 121 | id: mainCol | ||
134 | anchors.fill: parent | 122 | anchors.fill: parent | ||
135 | 123 | | |||
136 | Item { // Album Art Background + Details | 124 | Item { // Album Art Background + Details | ||
137 | Layout.fillWidth: true | 125 | Layout.fillWidth: true | ||
138 | Layout.fillHeight: true | 126 | Layout.fillHeight: true | ||
139 | 127 | | |||
140 | Image { | 128 | Image { | ||
141 | id: backgroundImage | 129 | id: backgroundImage | ||
142 | 130 | | |||
143 | source: root.albumArt | 131 | source: Media.albumArt | ||
144 | sourceSize.width: 512 /* | 132 | sourceSize.width: 512 /* | ||
145 | * Setting a sourceSize.width here | 133 | * Setting a sourceSize.width here | ||
146 | * prevents flickering when resizing the | 134 | * prevents flickering when resizing the | ||
147 | * plasmoid on a desktop. | 135 | * plasmoid on a desktop. | ||
148 | */ | 136 | */ | ||
149 | 137 | | |||
150 | anchors.fill: parent | 138 | anchors.fill: parent | ||
151 | anchors.margins: -units.smallSpacing*2 | 139 | anchors.margins: -units.smallSpacing*2 | ||
152 | fillMode: Image.PreserveAspectCrop | 140 | fillMode: Image.PreserveAspectCrop | ||
153 | 141 | | |||
154 | asynchronous: true | 142 | asynchronous: true | ||
155 | visible: !!root.track && status === Image.Ready && !softwareRendering | 143 | visible: Media.hasCurrentTrack && status === Image.Ready && !softwareRendering | ||
156 | 144 | | |||
157 | layer.enabled: !softwareRendering | 145 | layer.enabled: !softwareRendering | ||
158 | layer.effect: HueSaturation { | 146 | layer.effect: HueSaturation { | ||
159 | cached: true | 147 | cached: true | ||
160 | 148 | | |||
161 | lightness: -0.5 | 149 | lightness: -0.5 | ||
162 | saturation: 0.9 | 150 | saturation: 0.9 | ||
163 | 151 | | |||
Show All 25 Lines | 175 | Item { | |||
189 | Layout.fillHeight: true | 177 | Layout.fillHeight: true | ||
190 | Layout.preferredWidth: 50 | 178 | Layout.preferredWidth: 50 | ||
191 | 179 | | |||
192 | Image { // Album Art | 180 | Image { // Album Art | ||
193 | id: albumArt | 181 | id: albumArt | ||
194 | 182 | | |||
195 | anchors.fill: parent | 183 | anchors.fill: parent | ||
196 | 184 | | |||
197 | visible: !!root.track && status === Image.Ready | 185 | visible: Media.hasAlbumArt && status === Image.Ready | ||
198 | 186 | | |||
199 | asynchronous: true | 187 | asynchronous: true | ||
200 | 188 | | |||
201 | horizontalAlignment: Image.AlignRight | 189 | horizontalAlignment: Image.AlignRight | ||
202 | verticalAlignment: Image.AlignVCenter | 190 | verticalAlignment: Image.AlignVCenter | ||
203 | fillMode: Image.PreserveAspectFit | 191 | fillMode: Image.PreserveAspectFit | ||
204 | 192 | | |||
205 | source: root.albumArt | 193 | source: Media.albumArt | ||
206 | } | 194 | } | ||
207 | 195 | | |||
208 | PlasmaCore.IconItem { // Fallback | 196 | PlasmaCore.IconItem { // Fallback | ||
209 | visible: !albumArt.visible | 197 | visible: !albumArt.visible | ||
210 | source: { | 198 | source: Media.fallbackIcon | ||
211 | if (mpris2Source.currentData["Desktop Icon Name"]) | | |||
212 | return mpris2Source.currentData["Desktop Icon Name"] | | |||
213 | return "media-album-cover" | | |||
214 | } | | |||
215 | 199 | | |||
216 | anchors { | 200 | anchors { | ||
217 | fill: parent | 201 | fill: parent | ||
218 | margins: units.largeSpacing*2 | 202 | margins: units.largeSpacing*2 | ||
219 | } | 203 | } | ||
220 | } | 204 | } | ||
221 | } | 205 | } | ||
222 | 206 | | |||
223 | ColumnLayout { // Details Column | 207 | ColumnLayout { // Details Column | ||
224 | Layout.fillWidth: true | 208 | Layout.fillWidth: true | ||
225 | Layout.fillHeight: true | 209 | Layout.fillHeight: true | ||
226 | Layout.preferredWidth: 50 | 210 | Layout.preferredWidth: 50 | ||
227 | Layout.alignment: !(albumArt.visible || !!mpris2Source.currentData["Desktop Icon Name"]) ? Qt.AlignHCenter : 0 | 211 | Layout.alignment: !(albumArt.visible || Media.current["Desktop Icon Name"]) ? Qt.AlignHCenter : 0 | ||
228 | 212 | | |||
229 | /* | 213 | /* | ||
230 | * We use Kirigami.Heading instead of PlasmaExtras.Heading | 214 | * We use Kirigami.Heading instead of PlasmaExtras.Heading | ||
231 | * to prevent a binding loop caused by the PC2 Label component | 215 | * to prevent a binding loop caused by the PC2 Label component | ||
232 | * used by PlasmaExtras.Heading | 216 | * used by PlasmaExtras.Heading | ||
233 | */ | 217 | */ | ||
234 | Kirigami.Heading { // Song Title | 218 | Kirigami.Heading { // Song Title | ||
235 | id: songTitle | 219 | id: songTitle | ||
236 | level: 1 | 220 | level: 1 | ||
237 | 221 | | |||
238 | color: (softwareRendering || !albumArt.visible) ? PlasmaCore.ColorScope.textColor : "white" | 222 | color: (softwareRendering || !albumArt.visible) ? PlasmaCore.ColorScope.textColor : "white" | ||
239 | 223 | | |||
240 | textFormat: Text.PlainText | 224 | textFormat: Text.PlainText | ||
241 | wrapMode: Text.Wrap | 225 | wrapMode: Text.Wrap | ||
242 | fontSizeMode: Text.VerticalFit | 226 | fontSizeMode: Text.VerticalFit | ||
243 | elide: Text.ElideRight | 227 | elide: Text.ElideRight | ||
244 | 228 | | |||
245 | text: root.track || i18n("No media playing") | 229 | text: Media.hasCurrentTrack ? Media.currentTrack : i18n("No media playing") | ||
246 | 230 | | |||
247 | Layout.fillWidth: true | 231 | Layout.fillWidth: true | ||
248 | Layout.maximumHeight: units.gridUnit*5 | 232 | Layout.maximumHeight: units.gridUnit*5 | ||
249 | } | 233 | } | ||
250 | Kirigami.Heading { // Song Artist | 234 | Kirigami.Heading { // Song Artist | ||
251 | id: songArtist | 235 | id: songArtist | ||
252 | visible: root.track && root.artist | 236 | visible: Media.hasCurrentArtist | ||
253 | level: 2 | 237 | level: 2 | ||
254 | 238 | | |||
255 | color: (softwareRendering || !albumArt.visible) ? PlasmaCore.ColorScope.textColor : "white" | 239 | color: (softwareRendering || !albumArt.visible) ? PlasmaCore.ColorScope.textColor : "white" | ||
256 | 240 | | |||
257 | textFormat: Text.PlainText | 241 | textFormat: Text.PlainText | ||
258 | wrapMode: Text.Wrap | 242 | wrapMode: Text.Wrap | ||
259 | fontSizeMode: Text.VerticalFit | 243 | fontSizeMode: Text.VerticalFit | ||
260 | elide: Text.ElideRight | 244 | elide: Text.ElideRight | ||
261 | 245 | | |||
262 | text: root.artist | 246 | text: Media.currentArtist | ||
263 | Layout.fillWidth: true | 247 | Layout.fillWidth: true | ||
264 | Layout.maximumHeight: units.gridUnit*2 | 248 | Layout.maximumHeight: units.gridUnit*2 | ||
265 | } | 249 | } | ||
266 | Kirigami.Heading { // Song Album | 250 | Kirigami.Heading { // Song Album | ||
267 | color: (softwareRendering || !albumArt.visible) ? PlasmaCore.ColorScope.textColor : "white" | 251 | color: (softwareRendering || !albumArt.visible) ? PlasmaCore.ColorScope.textColor : "white" | ||
268 | 252 | | |||
269 | level: 3 | 253 | level: 3 | ||
270 | opacity: 0.6 | 254 | opacity: 0.6 | ||
271 | 255 | | |||
272 | textFormat: Text.PlainText | 256 | textFormat: Text.PlainText | ||
273 | wrapMode: Text.Wrap | 257 | wrapMode: Text.Wrap | ||
274 | fontSizeMode: Text.VerticalFit | 258 | fontSizeMode: Text.VerticalFit | ||
275 | elide: Text.ElideRight | 259 | elide: Text.ElideRight | ||
276 | 260 | | |||
277 | visible: text.length !== 0 | 261 | visible: text.length !== 0 | ||
278 | text: { | 262 | text: Media.currentAlbum | ||
279 | var metadata = root.currentMetadata | | |||
280 | if (!metadata) { | | |||
281 | return "" | | |||
282 | } | | |||
283 | var xesamAlbum = metadata["xesam:album"] | | |||
284 | if (xesamAlbum) { | | |||
285 | return xesamAlbum | | |||
286 | } | | |||
287 | | ||||
288 | // if we play a local file without title and artist, show its containing folder instead | | |||
289 | if (metadata["xesam:title"] || root.artist) { | | |||
290 | return "" | | |||
291 | } | | |||
292 | | ||||
293 | var xesamUrl = (metadata["xesam:url"] || "").toString() | | |||
294 | if (xesamUrl.indexOf("file:///") !== 0) { // "!startsWith()" | | |||
295 | return "" | | |||
296 | } | | |||
297 | | ||||
298 | var urlParts = xesamUrl.split("/") | | |||
299 | if (urlParts.length < 3) { | | |||
300 | return "" | | |||
301 | } | | |||
302 | | ||||
303 | var lastFolderPath = urlParts[urlParts.length - 2] // last would be filename | | |||
304 | if (lastFolderPath) { | | |||
305 | return lastFolderPath | | |||
306 | } | | |||
307 | | ||||
308 | return "" | | |||
309 | } | | |||
310 | Layout.fillWidth: true | 263 | Layout.fillWidth: true | ||
311 | Layout.maximumHeight: units.gridUnit*2 | 264 | Layout.maximumHeight: units.gridUnit*2 | ||
312 | } | 265 | } | ||
313 | } | 266 | } | ||
314 | } | 267 | } | ||
315 | } | 268 | } | ||
316 | 269 | | |||
317 | Item { | 270 | Item { | ||
318 | implicitHeight: units.smallSpacing | 271 | implicitHeight: units.smallSpacing | ||
319 | } | 272 | } | ||
320 | 273 | | |||
321 | RowLayout { // Seek Bar | 274 | RowLayout { // Seek Bar | ||
322 | spacing: units.smallSpacing | 275 | spacing: units.smallSpacing | ||
323 | 276 | | |||
324 | // if there's no "mpris:length" in the metadata, we cannot seek, so hide it in that case | 277 | // if there's no "mpris:length" in the metadata, we cannot seek, so hide it in that case | ||
325 | enabled: !root.noPlayer && root.track && expandedRepresentation.length > 0 ? true : false | 278 | enabled: !Media.noPlayers && Media.hasCurrentTrack && Media.songLength > 0 | ||
326 | opacity: enabled ? 1 : 0 | 279 | opacity: enabled ? 1 : 0 | ||
327 | Behavior on opacity { | 280 | Behavior on opacity { | ||
328 | NumberAnimation { duration: units.longDuration } | 281 | NumberAnimation { duration: units.longDuration } | ||
329 | } | 282 | } | ||
330 | 283 | | |||
331 | Layout.alignment: Qt.AlignHCenter | 284 | Layout.alignment: Qt.AlignHCenter | ||
332 | Layout.fillWidth: true | 285 | Layout.fillWidth: true | ||
333 | Layout.maximumWidth: Math.min(units.gridUnit*45, Math.round(expandedRepresentation.width*(7/10))) | 286 | Layout.maximumWidth: Math.min(units.gridUnit*45, Math.round(expandedRepresentation.width*(7/10))) | ||
Show All 16 Lines | 296 | PlasmaComponents3.Label { // Time Elapsed | |||
350 | color: PlasmaCore.ColorScope.textColor | 303 | color: PlasmaCore.ColorScope.textColor | ||
351 | } | 304 | } | ||
352 | 305 | | |||
353 | PlasmaComponents3.Slider { // Slider | 306 | PlasmaComponents3.Slider { // Slider | ||
354 | id: seekSlider | 307 | id: seekSlider | ||
355 | Layout.fillWidth: true | 308 | Layout.fillWidth: true | ||
356 | z: 999 | 309 | z: 999 | ||
357 | value: 0 | 310 | value: 0 | ||
358 | visible: canSeek | 311 | visible: Media.canSeek | ||
359 | 312 | | |||
360 | onMoved: { | 313 | onMoved: { | ||
361 | if (!disablePositionUpdate) { | 314 | if (!Media.lockPositionUpdate) { | ||
362 | // delay setting the position to avoid race conditions | 315 | // delay setting the position to avoid race conditions | ||
363 | queuedPositionUpdate.restart() | 316 | queuedPositionUpdate.restart() | ||
364 | } | 317 | } | ||
365 | } | 318 | } | ||
366 | 319 | | |||
367 | Timer { | 320 | Timer { | ||
368 | id: seekTimer | 321 | id: seekTimer | ||
369 | interval: 1000 / expandedRepresentation.rate | 322 | interval: 1000 / Media.playbackRate | ||
370 | repeat: true | 323 | repeat: true | ||
371 | running: root.state === "playing" && plasmoid.expanded && !keyPressed && interval > 0 && seekSlider.to >= 1000000 | 324 | running: Media.state === "playing" && plasmoid.expanded && !keyPressed && interval > 0 && seekSlider.to >= 1000000 | ||
372 | onTriggered: { | 325 | onTriggered: { | ||
373 | // some players don't continuously update the seek slider position via mpris | 326 | // some players don't continuously update the seek slider position via mpris | ||
374 | // add one second; value in microseconds | 327 | // add one second; value in microseconds | ||
375 | if (!seekSlider.pressed) { | 328 | if (!seekSlider.pressed) { | ||
376 | disablePositionUpdate = true | 329 | Media.lockPositionUpdate = true | ||
377 | if (seekSlider.value == seekSlider.to) { | 330 | if (seekSlider.value == seekSlider.to) { | ||
378 | retrievePosition(); | 331 | Media.retrievePosition() | ||
379 | } else { | 332 | } else { | ||
380 | seekSlider.value += 1000000 | 333 | seekSlider.value += 1000000 | ||
381 | } | 334 | } | ||
382 | disablePositionUpdate = false | 335 | Media.lockPositionUpdate = false | ||
383 | } | 336 | } | ||
384 | } | 337 | } | ||
385 | } | 338 | } | ||
386 | } | 339 | } | ||
387 | 340 | | |||
388 | RowLayout { | 341 | RowLayout { | ||
389 | visible: !canSeek | 342 | visible: !Media.canSeek | ||
390 | 343 | | |||
391 | Layout.fillWidth: true | 344 | Layout.fillWidth: true | ||
392 | Layout.preferredHeight: seekSlider.height | 345 | Layout.preferredHeight: seekSlider.height | ||
393 | 346 | | |||
394 | PlasmaComponents3.ProgressBar { // Time Remaining | 347 | PlasmaComponents3.ProgressBar { // Time Remaining | ||
395 | value: seekSlider.value | 348 | value: seekSlider.value | ||
396 | from: seekSlider.from | 349 | from: seekSlider.from | ||
397 | to: seekSlider.to | 350 | to: seekSlider.to | ||
Show All 14 Lines | 358 | PlasmaComponents3.Label { | |||
412 | font: theme.smallestFont | 365 | font: theme.smallestFont | ||
413 | color: PlasmaCore.ColorScope.textColor | 366 | color: PlasmaCore.ColorScope.textColor | ||
414 | } | 367 | } | ||
415 | } | 368 | } | ||
416 | 369 | | |||
417 | Row { // Player Controls | 370 | Row { // Player Controls | ||
418 | id: playerControls | 371 | id: playerControls | ||
419 | 372 | | |||
420 | property bool enabled: root.canControl | 373 | property bool enabled: Media.canControl | ||
421 | property int controlsSize: theme.mSize(theme.defaultFont).height * 3 | 374 | property int controlsSize: theme.mSize(theme.defaultFont).height * 3 | ||
422 | 375 | | |||
423 | Layout.alignment: Qt.AlignHCenter | 376 | Layout.alignment: Qt.AlignHCenter | ||
424 | spacing: units.largeSpacing | 377 | spacing: units.largeSpacing | ||
425 | 378 | | |||
426 | PlasmaComponents3.ToolButton { // Previous | 379 | PlasmaComponents3.ToolButton { // Previous | ||
427 | anchors.verticalCenter: parent.verticalCenter | 380 | anchors.verticalCenter: parent.verticalCenter | ||
428 | width: expandedRepresentation.controlSize | 381 | width: expandedRepresentation.controlSize | ||
429 | height: width | 382 | height: width | ||
430 | enabled: playerControls.enabled && root.canGoPrevious | 383 | enabled: playerControls.enabled && Media.canGoPrevious | ||
431 | icon.name: LayoutMirroring.enabled ? "media-skip-forward" : "media-skip-backward" | 384 | icon.name: LayoutMirroring.enabled ? "media-skip-forward" : "media-skip-backward" | ||
432 | onClicked: { | 385 | onClicked: { | ||
433 | seekSlider.value = 0 // Let the media start from beginning. Bug 362473 | 386 | seekSlider.value = 0 // Let the media start from beginning. Bug 362473 | ||
434 | root.action_previous() | 387 | Media.perform(Media.previous) | ||
435 | } | 388 | } | ||
436 | } | 389 | } | ||
437 | 390 | | |||
438 | PlasmaComponents3.ToolButton { // Pause/Play | 391 | PlasmaComponents3.ToolButton { // Pause/Play | ||
439 | width: Math.round(expandedRepresentation.controlSize * 1.5) | 392 | width: Math.round(expandedRepresentation.controlSize * 1.5) | ||
440 | height: width | 393 | height: width | ||
441 | enabled: root.state == "playing" ? root.canPause : root.canPlay | 394 | enabled: Media.state == "playing" ? Media.canPause : Media.canPlay | ||
442 | icon.name: root.state == "playing" ? "media-playback-pause" : "media-playback-start" | 395 | icon.name: Media.state == "playing" ? "media-playback-pause" : "media-playback-start" | ||
443 | onClicked: root.togglePlaying() | 396 | onClicked: Media.togglePlaying() | ||
444 | } | 397 | } | ||
445 | 398 | | |||
446 | PlasmaComponents3.ToolButton { // Next | 399 | PlasmaComponents3.ToolButton { // Next | ||
447 | anchors.verticalCenter: parent.verticalCenter | 400 | anchors.verticalCenter: parent.verticalCenter | ||
448 | width: expandedRepresentation.controlSize | 401 | width: expandedRepresentation.controlSize | ||
449 | height: width | 402 | height: width | ||
450 | enabled: playerControls.enabled && root.canGoNext | 403 | enabled: playerControls.enabled && Media.canGoNext | ||
451 | icon.name: LayoutMirroring.enabled ? "media-skip-backward" : "media-skip-forward" | 404 | icon.name: LayoutMirroring.enabled ? "media-skip-backward" : "media-skip-forward" | ||
452 | onClicked: { | 405 | onClicked: { | ||
453 | seekSlider.value = 0 // Let the media start from beginning. Bug 362473 | 406 | seekSlider.value = 0 // Let the media start from beginning. Bug 362473 | ||
454 | root.action_next() | 407 | Media.perform(Media.next) | ||
455 | } | 408 | } | ||
456 | } | 409 | } | ||
457 | } | 410 | } | ||
458 | 411 | | |||
459 | PlasmaComponents3.ComboBox { | 412 | PlasmaComponents3.ComboBox { | ||
460 | Layout.fillWidth: true | 413 | Layout.fillWidth: true | ||
461 | Layout.leftMargin: units.gridUnit*2 | 414 | Layout.leftMargin: units.gridUnit*2 | ||
462 | Layout.rightMargin: units.gridUnit*2 | 415 | Layout.rightMargin: units.gridUnit*2 | ||
463 | 416 | | |||
464 | id: playerCombo | 417 | id: playerCombo | ||
465 | textRole: "text" | 418 | textRole: "text" | ||
466 | visible: model.length > 2 // more than one player, @multiplex is always there | 419 | visible: model.length > 2 // more than one player, @multiplex is always there | ||
467 | model: root.mprisSourcesModel | 420 | model: Media.sources | ||
468 | 421 | | |||
469 | onModelChanged: { | 422 | onModelChanged: { | ||
470 | // if model changes, ComboBox resets, so we try to find the current player again... | 423 | // if model changes, ComboBox resets, so we try to find the current player again... | ||
471 | for (var i = 0, length = model.length; i < length; ++i) { | 424 | for (var i = 0; i < model.length; ++i) { | ||
472 | if (model[i].source === mpris2Source.current) { | 425 | if (model[i].source === Media.source.current) { | ||
473 | currentIndex = i | 426 | currentIndex = i | ||
474 | break | 427 | break | ||
475 | } | 428 | } | ||
476 | } | 429 | } | ||
477 | } | 430 | } | ||
478 | 431 | | |||
479 | onActivated: { | 432 | onActivated: { | ||
480 | disablePositionUpdate = true | 433 | Media.lockPositionUpdate = true | ||
481 | // ComboBox has currentIndex and currentText, why doesn't it have currentItem/currentModelValue? | 434 | // ComboBox has currentIndex and currentText, why doesn't it have currentItem/currentModelValue? | ||
482 | mpris2Source.current = model[index].source | 435 | Media.currentSource = model[index].source | ||
483 | disablePositionUpdate = false | 436 | Media.lockPositionUpdate = false | ||
484 | } | 437 | } | ||
485 | } | 438 | } | ||
486 | } | 439 | } | ||
487 | 440 | | |||
488 | Timer { | 441 | Timer { | ||
489 | id: queuedPositionUpdate | 442 | id: queuedPositionUpdate | ||
490 | interval: 100 | 443 | interval: 100 | ||
491 | onTriggered: { | 444 | onTriggered: { | ||
492 | if (position == seekSlider.value) { | 445 | if (Media.position == seekSlider.value) { | ||
493 | return; | 446 | return | ||
494 | } | 447 | } | ||
495 | var service = mpris2Source.serviceForSource(mpris2Source.current) | 448 | Media.setPosition(seekSlider.value) | ||
496 | var operation = service.operationDescription("SetPosition") | | |||
497 | operation.microseconds = seekSlider.value | | |||
498 | service.startOperationCall(operation) | | |||
499 | } | 449 | } | ||
500 | } | 450 | } | ||
501 | } | 451 | } |
Coding style, space