Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
nheko
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Nheko Reborn
nheko
Commits
42b74509
Verified
Commit
42b74509
authored
3 years ago
by
Joe Donofry
Browse files
Options
Downloads
Patches
Plain Diff
Incorporate nico's suggestions, fix volume slider
parent
13a5194c
No related branches found
Branches containing commit
No related tags found
Tags containing commit
1 merge request
!15
Video player enhancements
Pipeline
#2011
passed
3 years ago
Stage: build
Changes
1
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
resources/qml/delegates/PlayableMediaMessage.qml
+272
-272
272 additions, 272 deletions
resources/qml/delegates/PlayableMediaMessage.qml
with
272 additions
and
272 deletions
resources/qml/delegates/PlayableMediaMessage.qml
+
272
−
272
View file @
42b74509
...
...
@@ -20,23 +20,24 @@ ColumnLayout {
required
property
string
filesize
function
durationToString
(
duration
)
{
function
maybeZeroPrepend
(
time
)
{
return
(
time
<
10
)
?
"
0
"
+
time
.
toString
()
:
time
.
toString
()
}
var
totalSeconds
=
Math
.
floor
(
duration
/
1000
)
var
seconds
=
totalSeconds
%
60
var
minutes
=
(
Math
.
floor
(
totalSeconds
/
60
))
%
60
var
hours
=
(
Math
.
floor
(
totalSeconds
/
(
60
*
24
)))
%
24
// Always show minutes and don't prepend zero into the leftmost element
var
ss
=
maybeZeroPrepend
(
seconds
)
var
mm
=
(
hours
>
0
)
?
maybeZeroPrepend
(
minutes
)
:
minutes
.
toString
()
var
hh
=
hours
.
toString
()
function
maybeZeroPrepend
(
time
)
{
return
(
time
<
10
)
?
"
0
"
+
time
.
toString
()
:
time
.
toString
()
}
var
totalSeconds
=
Math
.
floor
(
duration
/
1000
)
var
seconds
=
totalSeconds
%
60
var
minutes
=
(
Math
.
floor
(
totalSeconds
/
60
))
%
60
var
hours
=
(
Math
.
floor
(
totalSeconds
/
(
60
*
24
)))
%
24
// Always show minutes and don't prepend zero into the leftmost element
var
ss
=
maybeZeroPrepend
(
seconds
)
var
mm
=
(
hours
>
0
)
?
maybeZeroPrepend
(
minutes
)
:
minutes
.
toString
()
var
hh
=
hours
.
toString
()
if
(
hours
<
1
)
return
mm
+
"
:
"
+
ss
return
hh
+
"
:
"
+
mm
+
"
:
"
+
ss
}
if
(
hours
<
1
)
{
return
mm
+
"
:
"
+
ss
}
return
hh
+
"
:
"
+
mm
+
"
:
"
+
ss
}
id
:
content
...
...
@@ -46,8 +47,11 @@ ColumnLayout {
// TODO: Show error in overlay or so?
onError
:
console
.
log
(
error
)
roomm
:
room
// desiredVolume is a float from 0.0 -> 1.0, MediaPlayer volume is an int from 0 to 100
// this value automatically gets clamped for us between these two values.
volume
:
volumeSlider
.
desiredVolume
*
100
}
Rectangle
{
id
:
videoContainer
visible
:
type
==
MtxEvent
.
VideoMessage
...
...
@@ -60,6 +64,7 @@ ColumnLayout {
property
double
divisor
:
isReply
?
4
:
2
property
bool
tooHigh
:
tempHeight
>
timelineRoot
.
height
/
divisor
color
:
Nheko
.
colors
.
window
Layout.preferredHeight
:
tooHigh
?
timelineRoot
.
height
/
divisor
:
tempHeight
Layout.preferredWidth
:
tooHigh
?
(
timelineRoot
.
height
/
divisor
)
/
proportionalHeight
:
tempWidth
...
...
@@ -71,16 +76,16 @@ ColumnLayout {
asynchronous
:
true
fillMode
:
Image
.
PreserveAspectFit
// Button and window colored overlay to cache media
Rectangle
{
Item
{
// Display over video controls
z
:
videoOutput
.
z
+
1
visible
:
!
mxcmedia
.
loaded
anchors.fill
:
parent
color
:
Nheko
.
colors
.
window
opacity
:
0.5
//
color: Nheko.colors.window
//
opacity: 0.5
Image
{
property
color
buttonColor
:
(
cacheVideoArea
.
containsMouse
)
?
Nheko
.
colors
.
highlight
:
Nheko
.
colors
.
text
Nheko
.
colors
.
text
anchors.verticalCenter
:
parent
.
verticalCenter
anchors.horizontalCenter
:
parent
.
horizontalCenter
...
...
@@ -100,7 +105,7 @@ ColumnLayout {
anchors.fill
:
parent
fillMode
:
VideoOutput
.
PreserveAspectFit
source
:
mxcmedia
flushMode
:
VideoOutput
.
FirstFrame
flushMode
:
VideoOutput
.
FirstFrame
// TODO: once we can use Qt 5.12, use HoverHandler
MouseArea
{
...
...
@@ -108,267 +113,262 @@ ColumnLayout {
// Toggle play state on clicks
onClicked
:
{
if
(
controlRect
.
shouldShowControls
&&
!
controlRect
.
contains
(
mapToItem
(
controlRect
,
mouseX
,
mouseY
)))
{
(
mxcmedia
.
state
==
MediaPlayer
.
PlayingState
)
?
mxcmedia
.
pause
()
:
mxcmedia
.
play
()
!
controlRect
.
contains
(
mapToItem
(
controlRect
,
mouseX
,
mouseY
)))
{
(
mxcmedia
.
state
==
MediaPlayer
.
PlayingState
)
?
mxcmedia
.
pause
()
:
mxcmedia
.
play
()
}
}
Rectangle
{
id
:
controlRect
property
int
controlHeight
:
25
property
bool
shouldShowControls
:
playerMouseArea
.
shouldShowControls
||
volumeSliderRect
.
visible
Rectangle
{
id
:
controlRect
property
int
controlHeight
:
25
property
bool
shouldShowControls
:
playerMouseArea
.
shouldShowControls
||
volumeSliderRect
.
visible
anchors.bottom
:
playerMouseArea
.
bottom
// Window color with 128/255 alpha
color
:
{
var
wc
=
Nheko
.
colors
.
window
return
Qt
.
rgba
(
wc
.
r
,
wc
.
g
,
wc
.
b
,
0.5
)
}
height
:
40
width
:
playerMouseArea
.
width
opacity
:
shouldShowControls
?
1
:
0
// Fade controls in/out
Behavior
on
opacity
{
OpacityAnimator
{
duration
:
100
}
}
anchors.bottom
:
playerMouseArea
.
bottom
// Window color with 128/255 alpha
color
:
{
var
wc
=
Nheko
.
colors
.
alternateBase
return
Qt
.
rgba
(
wc
.
r
,
wc
.
g
,
wc
.
b
,
0.5
)
}
height
:
40
width
:
playerMouseArea
.
width
opacity
:
shouldShowControls
?
1
:
0
// Fade controls in/out
Behavior
on
opacity
{
OpacityAnimator
{
duration
:
100
}
}
RowLayout
{
anchors.fill
:
parent
width
:
parent
.
width
// Play/pause button
Image
{
id
:
playbackStateImage
fillMode
:
Image
.
PreserveAspectFit
Layout.preferredHeight
:
controlRect
.
controlHeight
Layout.alignment
:
Qt
.
AlignVCenter
property
color
controlColor
:
(
playbackStateArea
.
containsMouse
)
?
Nheko
.
colors
.
highlight
:
Nheko
.
colors
.
text
RowLayout
{
anchors.fill
:
parent
width
:
parent
.
width
// Play/pause button
Image
{
id
:
playbackStateImage
fillMode
:
Image
.
PreserveAspectFit
Layout.preferredHeight
:
controlRect
.
controlHeight
Layout.alignment
:
Qt
.
AlignVCenter
property
color
controlColor
:
(
playbackStateArea
.
containsMouse
)
?
Nheko
.
colors
.
highlight
:
Nheko
.
colors
.
text
source
:
(
mxcmedia
.
state
==
MediaPlayer
.
PlayingState
)
?
"
image://colorimage/:/icons/icons/ui/pause-symbol.png?
"
+
controlColor
:
"
image://colorimage/:/icons/icons/ui/play-sign.png?
"
+
controlColor
MouseArea
{
id
:
playbackStateArea
anchors.fill
:
parent
hoverEnabled
:
true
onClicked
:
{
(
mxcmedia
.
state
==
MediaPlayer
.
PlayingState
)
?
mxcmedia
.
pause
()
:
mxcmedia
.
play
()
}
}
}
Label
{
text
:
(
!
mxcmedia
.
loaded
)
?
"
-/-
"
:
durationToString
(
mxcmedia
.
position
)
+
"
/
"
+
durationToString
(
mxcmedia
.
duration
)
}
source
:
(
mxcmedia
.
state
==
MediaPlayer
.
PlayingState
)
?
"
image://colorimage/:/icons/icons/ui/pause-symbol.png?
"
+
controlColor
:
"
image://colorimage/:/icons/icons/ui/play-sign.png?
"
+
controlColor
MouseArea
{
id
:
playbackStateArea
Slider
{
Layout.fillWidth
:
true
Layout.minimumWidth
:
50
height
:
controlRect
.
controlHeight
value
:
mxcmedia
.
p
osition
onMoved
:
mxcmedia
.
position
=
value
from
:
0
to
:
mxcmedia
.
duration
}
// Volume slider activator
Image
{
property
color
controlColor
:
(
volumeImageArea
.
containsMouse
)
?
Nheko
.
colors
.
highlight
:
Nheko
.
colors
.
text
anchors.fill
:
parent
hoverEnabled
:
true
onClicked
:
{
(
mxcmedia
.
state
==
MediaPlayer
.
PlayingState
)
?
mxcmedia
.
p
ause
()
:
mxcmedia
.
play
()
}
}
}
Label
{
text
:
(
!
mxcmedia
.
loaded
)
?
"
-/-
"
:
(
durationToString
(
mxcmedia
.
position
)
+
"
/
"
+
durationToString
(
mxcmedia
.
duration
))
color
:
Nheko
.
colors
.
text
}
// TODO: add icons for different volume levels
id
:
volumeImage
source
:
(
mxcmedia
.
volume
>
0
&&
!
mxcmedia
.
muted
)
?
"
image://colorimage/:/icons/icons/ui/volume-up.png?
"
+
controlColor
:
"
image://colorimage/:/icons/icons/ui/volume-off-indicator.png?
"
+
controlColor
Layout.rightMargin
:
5
Layout.preferredHeight
:
controlRect
.
controlHeight
fillMode
:
Image
.
PreserveAspectFit
MouseArea
{
id
:
volumeImageArea
anchors.fill
:
parent
hoverEnabled
:
true
onClicked
:
mxcmedia
.
muted
=
!
mxcmedia
.
muted
onExited
:
volumeSliderHideTimer
.
start
()
onPositionChanged
:
volumeSliderHideTimer
.
start
()
// For hiding volume slider after a while
Timer
{
id
:
volumeSliderHideTimer
interval
:
1500
repeat
:
false
running
:
false
}
}
Rectangle
{
id
:
volumeSliderRect
opacity
:
(
visible
)
?
1
:
0
Behavior
on
opacity
{
OpacityAnimator
{
duration
:
100
}
}
// TODO: figure out a better way to put the slider popup above controlRect
anchors.bottom
:
volumeImage
.
top
anchors.bottomMargin
:
10
anchors.horizontalCenter
:
volumeImage
.
horizontalCenter
color
:
{
var
wc
=
Nheko
.
colors
.
window
return
Qt
.
rgba
(
wc
.
r
,
wc
.
g
,
wc
.
b
,
0.5
)
}
/* TODO: base width on the slider width (some issue with it not having a geometry
when using the width here?) */
width
:
volumeImage
.
width
*
0.7
radius
:
volumeSlider
.
width
/
2
height
:
controlRect
.
height
*
2
//100
visible
:
volumeImageArea
.
containsMouse
||
volumeSliderHideTimer
.
running
||
volumeSliderRectMouseArea
.
containsMouse
Slider
{
// Desired value to avoid loop onMoved -> media.volume -> value -> onMoved...
property
real
desiredVolume
:
1
// TODO: the slider is slightly off-center on the left for some reason...
id
:
volumeSlider
from
:
0
to
:
1
value
:
(
mxcmedia
.
muted
)
?
0
:
QtMultimedia
.
convertVolume
(
desiredVolume
,
QtMultimedia
.
LinearVolumeScale
,
QtMultimedia
.
LogarithmicVolumeScale
)
anchors.fill
:
parent
anchors.bottomMargin
:
parent
.
height
*
0.1
anchors.topMargin
:
parent
.
height
*
0.1
anchors.horizontalCenter
:
parent
.
horizontalCenter
orientation
:
Qt
.
Vertical
onMoved
:
desiredVolume
=
QtMultimedia
.
convertVolume
(
value
,
QtMultimedia
.
LogarithmicVolumeScale
,
QtMultimedia
.
LinearVolumeScale
)
/* This would be better handled in 'media', but it has some issue with listening
to this signal */
onDesiredVolumeChanged
:
mxcmedia
.
muted
=
!
(
desiredVolume
>
0
)
}
// Used for resetting the timer on mouse moves on volumeSliderRect
MouseArea
{
id
:
volumeSliderRectMouseArea
anchors.fill
:
parent
hoverEnabled
:
true
propagateComposedEvents
:
true
onExited
:
volumeSliderHideTimer
.
start
()
Slider
{
Layout.fillWidth
:
true
Layout.minimumWidth
:
50
height
:
controlRect
.
controlHeight
value
:
mxcmedia
.
position
onMoved
:
mxcmedia
.
position
=
value
from
:
0
to
:
mxcmedia
.
duration
}
// Volume slider activator
Image
{
property
color
controlColor
:
(
volumeImageArea
.
containsMouse
)
?
Nheko
.
colors
.
highlight
:
Nheko
.
colors
.
text
onClicked
:
mouse
.
accepted
=
false
onPressed
:
mouse
.
accepted
=
false
onReleased
:
mouse
.
accepted
=
false
onPressAndHold
:
mouse
.
accepted
=
false
onPositionChanged
:
{
mouse
.
accepted
=
false
volumeSliderHideTimer
.
start
()
}
}
}
}
// TODO: add icons for different volume levels
id
:
volumeImage
source
:
(
mxcmedia
.
volume
>
0
&&
!
mxcmedia
.
muted
)
?
"
image://colorimage/:/icons/icons/ui/volume-up.png?
"
+
controlColor
:
"
image://colorimage/:/icons/icons/ui/volume-off-indicator.png?
"
+
controlColor
Layout.rightMargin
:
5
Layout.preferredHeight
:
controlRect
.
controlHeight
fillMode
:
Image
.
PreserveAspectFit
MouseArea
{
id
:
volumeImageArea
anchors.fill
:
parent
hoverEnabled
:
true
onClicked
:
mxcmedia
.
muted
=
!
mxcmedia
.
muted
onExited
:
volumeSliderHideTimer
.
start
()
onPositionChanged
:
volumeSliderHideTimer
.
start
()
// For hiding volume slider after a while
Timer
{
id
:
volumeSliderHideTimer
interval
:
1500
repeat
:
false
running
:
false
}
}
Rectangle
{
id
:
volumeSliderRect
opacity
:
(
visible
)
?
1
:
0
Behavior
on
opacity
{
OpacityAnimator
{
duration
:
100
}
}
// TODO: figure out a better way to put the slider popup above controlRect
anchors.bottom
:
volumeImage
.
top
anchors.bottomMargin
:
10
anchors.horizontalCenter
:
volumeImage
.
horizontalCenter
color
:
{
var
wc
=
Nheko
.
colors
.
window
return
Qt
.
rgba
(
wc
.
r
,
wc
.
g
,
wc
.
b
,
0.5
)
}
/* TODO: base width on the slider width (some issue with it not having a geometry
when using the width here?) */
width
:
volumeImage
.
width
*
0.7
radius
:
volumeSlider
.
width
/
2
height
:
controlRect
.
height
*
2
//100
visible
:
volumeImageArea
.
containsMouse
||
volumeSliderHideTimer
.
running
||
volumeSliderRectMouseArea
.
containsMouse
Slider
{
// TODO: the slider is slightly off-center on the left for some reason...
id
:
volumeSlider
}
}
// This breaks separation of concerns but this same thing doesn't work when called from controlRect...
property
bool
shouldShowControls
:
(
containsMouse
&&
controlHideTimer
.
running
)
||
(
mxcmedia
.
state
!=
MediaPlayer
.
PlayingState
)
||
controlRect
.
contains
(
mapToItem
(
controlRect
,
mouseX
,
mouseY
))
value
:
1.0
// Desired value to avoid loop onMoved -> media.volume -> value -> onMoved...
property
real
desiredVolume
:
QtMultimedia
.
convertVolume
(
volumeSlider
.
value
,
QtMultimedia
.
LogarithmicVolumeScale
,
QtMultimedia
.
LinearVolumeScale
)
// For hiding controls on stationary cursor
Timer
{
id
:
controlHideTimer
interval
:
1500
//ms
repeat
:
false
}
anchors.fill
:
parent
anchors.bottomMargin
:
parent
.
height
*
0.1
anchors.topMargin
:
parent
.
height
*
0.1
anchors.horizontalCenter
:
parent
.
horizontalCenter
orientation
:
Qt
.
Vertical
onDesiredVolumeChanged
:
{
mxcmedia
.
muted
=
!
(
desiredVolume
>
0.0
)
}
}
// Used for resetting the timer on mouse moves on volumeSliderRect
MouseArea
{
id
:
volumeSliderRectMouseArea
anchors.fill
:
parent
hoverEnabled
:
true
propagateComposedEvents
:
true
onExited
:
volumeSliderHideTimer
.
start
()
hoverEnabled
:
true
onPositionChanged
:
controlHideTimer
.
start
()
onClicked
:
mouse
.
accepted
=
false
onPressed
:
mouse
.
accepted
=
false
onReleased
:
mouse
.
accepted
=
false
onPressAndHold
:
mouse
.
accepted
=
false
onPositionChanged
:
{
mouse
.
accepted
=
false
volumeSliderHideTimer
.
start
()
}
}
}
}
x
:
videoOutput
.
contentRect
.
x
y
:
videoOutput
.
contentRect
.
y
width
:
videoOutput
.
contentRect
.
width
height
:
videoOutput
.
contentRect
.
height
propagateComposedEvents
:
true
}
}
}
}
// Audio player
// TODO: share code with the video player
Rectangle
{
id
:
audioControlRect
visible
:
type
!=
MtxEvent
.
VideoMessage
property
int
controlHeight
:
25
Layout.preferredHeight
:
40
RowLayout
{
anchors.fill
:
parent
width
:
parent
.
width
// Play/pause button
Image
{
id
:
audioPlaybackStateImage
fillMode
:
Image
.
PreserveAspectFit
Layout.preferredHeight
:
controlRect
.
controlHeight
Layout.alignment
:
Qt
.
AlignVCenter
property
color
controlColor
:
(
audioPlaybackStateArea
.
containsMouse
)
?
Nheko
.
colors
.
highlight
:
Nheko
.
colors
.
text
}
}
// This breaks separation of concerns but this same thing doesn't work when called from controlRect...
property
bool
shouldShowControls
:
(
containsMouse
&&
controlHideTimer
.
running
)
||
(
mxcmedia
.
state
!=
MediaPlayer
.
PlayingState
)
||
controlRect
.
contains
(
mapToItem
(
controlRect
,
mouseX
,
mouseY
))
source
:
{
if
(
!
mxcmedia
.
loaded
)
return
"
image://colorimage/:/icons/icons/ui/arrow-pointing-down.png?
"
+
controlColor
return
(
mxcmedia
.
state
==
MediaPlayer
.
PlayingState
)
?
"
image://colorimage/:/icons/icons/ui/pause-symbol.png?
"
+
controlColor
:
"
image://colorimage/:/icons/icons/ui/play-sign.png?
"
+
controlColor
}
MouseArea
{
id
:
audioPlaybackStateArea
anchors.fill
:
parent
hoverEnabled
:
true
onClicked
:
{
if
(
!
mxcmedia
.
loaded
)
{
mxcmedia
.
eventId
=
eventId
return
}
(
mxcmedia
.
state
==
MediaPlayer
.
PlayingState
)
?
mxcmedia
.
pause
()
:
mxcmedia
.
play
()
}
}
}
Label
{
text
:
(
!
mxcmedia
.
loaded
)
?
"
-/-
"
:
durationToString
(
mxcmedia
.
position
)
+
"
/
"
+
durationToString
(
mxcmedia
.
duration
)
}
// For hiding controls on stationary cursor
Timer
{
id
:
controlHideTimer
interval
:
1500
//ms
repeat
:
false
}
Slider
{
Layout.fillWidth
:
true
Layout.minimumWidth
:
50
height
:
controlRect
.
controlHeight
value
:
mxcmedia
.
position
onMoved
:
mxcmedia
.
seek
(
value
)
from
:
0
to
:
mxcmedia
.
duration
}
}
}
Label
{
id
:
fileInfoLabel
background
:
Rectangle
{
color
:
Nheko
.
colors
.
base
}
Layout.fillWidth
:
true
text
:
body
+
"
[
"
+
filesize
+
"
]
"
textFormat
:
Text
.
PlainText
elide
:
Text
.
ElideRight
color
:
Nheko
.
colors
.
text
}
}
hoverEnabled
:
true
onPositionChanged
:
controlHideTimer
.
start
()
x
:
videoOutput
.
contentRect
.
x
y
:
videoOutput
.
contentRect
.
y
width
:
videoOutput
.
contentRect
.
width
height
:
videoOutput
.
contentRect
.
height
propagateComposedEvents
:
true
}
}
}
}
// Audio player
// TODO: share code with the video player
Rectangle
{
id
:
audioControlRect
visible
:
type
!=
MtxEvent
.
VideoMessage
property
int
controlHeight
:
25
Layout.preferredHeight
:
40
RowLayout
{
anchors.fill
:
parent
width
:
parent
.
width
// Play/pause button
Image
{
id
:
audioPlaybackStateImage
fillMode
:
Image
.
PreserveAspectFit
Layout.preferredHeight
:
controlRect
.
controlHeight
Layout.alignment
:
Qt
.
AlignVCenter
property
color
controlColor
:
(
audioPlaybackStateArea
.
containsMouse
)
?
Nheko
.
colors
.
highlight
:
Nheko
.
colors
.
text
source
:
{
if
(
!
mxcmedia
.
loaded
)
return
"
image://colorimage/:/icons/icons/ui/arrow-pointing-down.png?
"
+
controlColor
return
(
mxcmedia
.
state
==
MediaPlayer
.
PlayingState
)
?
"
image://colorimage/:/icons/icons/ui/pause-symbol.png?
"
+
controlColor
:
"
image://colorimage/:/icons/icons/ui/play-sign.png?
"
+
controlColor
}
MouseArea
{
id
:
audioPlaybackStateArea
anchors.fill
:
parent
hoverEnabled
:
true
onClicked
:
{
if
(
!
mxcmedia
.
loaded
)
{
mxcmedia
.
eventId
=
eventId
return
}
(
mxcmedia
.
state
==
MediaPlayer
.
PlayingState
)
?
mxcmedia
.
pause
()
:
mxcmedia
.
play
()
}
}
}
Label
{
text
:
(
!
mxcmedia
.
loaded
)
?
"
-/-
"
:
durationToString
(
mxcmedia
.
position
)
+
"
/
"
+
durationToString
(
mxcmedia
.
duration
)
}
Slider
{
Layout.fillWidth
:
true
Layout.minimumWidth
:
50
height
:
controlRect
.
controlHeight
value
:
mxcmedia
.
position
onMoved
:
mxcmedia
.
seek
(
value
)
from
:
0
to
:
mxcmedia
.
duration
}
}
}
Label
{
id
:
fileInfoLabel
background
:
Rectangle
{
color
:
Nheko
.
colors
.
base
}
Layout.fillWidth
:
true
text
:
body
+
"
[
"
+
filesize
+
"
]
"
textFormat
:
Text
.
PlainText
elide
:
Text
.
ElideRight
color
:
Nheko
.
colors
.
text
}
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment