Advertisement
Guest User

VolumeControl.qml

a guest
Dec 21st, 2021
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
QML 20.71 KB | None | 0 0
  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2013 Jolla Ltd.
  4. ** Contact: Vesa Halttunen <vesa.halttunen@jollamobile.com>
  5. **
  6. ****************************************************************************/
  7.  
  8. import QtQuick 2.0
  9. import org.nemomobile.lipstick 0.1
  10. import Sailfish.Silica 1.0
  11. import org.nemomobile.systemsettings 1.0
  12. import org.nemomobile.configuration 1.0
  13. import com.jolla.lipstick 0.1
  14. import org.nemomobile.mpris 1.0
  15. import QtFeedback 5.0
  16. import "../systemwindow"
  17.  
  18. SystemWindow {
  19.     id: volumeBar
  20.  
  21.     MprisManager { id: mprisManager }
  22.    
  23.     property bool volumeIncreasing
  24.     property bool lateScreenshotCapture
  25.     property var screenshot
  26.     property bool controllingMedia: forceMediaVolume.value ||
  27.                                     volumeControl.mediaState === VolumeControl.MediaStateActive ||
  28.                                     volumeControl.mediaState === VolumeControl.MediaStateForeground ||
  29.                                     volumeControl.mediaState === VolumeControl.MediaStateBackground ||
  30.                                     volumeControl.callActive || showContinuousVolume
  31.     property real statusBarPushDownY: volumeArea.y + volumeArea.height
  32.     property bool showContinuousVolume: false
  33.     property int maximumVolume: controllingMedia ? volumeControl.maximumVolume : 100
  34.     property real initialChange: 0
  35.     property bool disableSmoothChange: true
  36.     property real baseVolume
  37.     property real continuousVolume: {
  38.         // The maximum continuous volume that should be allowed. Plus one so that the warning is triggered.
  39.         var max = (controllingMedia && volumeControl.restrictedVolume !== volumeControl.maximumVolume)
  40.                     ? (volumeControl.restrictedVolume+1) : maximumVolume
  41.  
  42.         // delta ranges from -1 to 1 (ratio of window dimension plus direction)
  43.         // Triple rate of volume change as in practice will not reach these limits.
  44.         var d = Lipstick.compositor.volumeGestureFilterItem.delta
  45.         return Math.min(Math.max(baseVolume + 3*d*maximumVolume, 0), max)
  46.     }
  47.     onContinuousVolumeChanged: {
  48.         if (!Lipstick.compositor.volumeGestureFilterItem.active)
  49.             return
  50.  
  51.         // Gesture only controls media volume
  52.         if (Lipstick.compositor.volumeGestureFilterItem.deltaIncreasing) {
  53.             if (Math.floor(continuousVolume) === 0)
  54.                 volumeControl.volume = Math.ceil(continuousVolume)
  55.             else
  56.                 volumeControl.volume = Math.floor(continuousVolume)
  57.         } else {
  58.             volumeControl.volume = Math.ceil(continuousVolume)
  59.         }
  60.     }
  61.  
  62.     property color _foregroundColor: controllingMedia && (volumeControl.volume > volumeControl.safeVolume)
  63.                                     ? Theme.highlightDimmerColor
  64.                                     : Theme.primaryColor
  65.     property color _backgroundColor: controllingMedia && (volumeControl.volume > volumeControl.safeVolume)
  66.                                         ? Theme.primaryColor
  67.                                         : Theme.secondaryHighlightColor
  68.  
  69.     Behavior on _foregroundColor { ColorAnimation { } }
  70.     Behavior on _backgroundColor { ColorAnimation { } }
  71.  
  72.     // Place below other notifications
  73.     z: -1
  74.  
  75.     onControllingMediaChanged: {
  76.         keyRepeatDelay.stop
  77.         keyRepeat.stop()
  78.     }
  79.  
  80.     Component.onCompleted: {
  81.         Lipstick.compositor.volumeWarningVisible = Qt.binding(function (){ return loader.active })
  82.     }
  83.  
  84.     ProfileControl {
  85.         id: profileControl
  86.  
  87.         function adjustRingtoneVolume(amount) {
  88.             var effectiveVolume = (profile == "silent") ? 0 : ringerVolume
  89.             var newVolume = Math.max(Math.min(effectiveVolume + amount, 100), 0)
  90.             var newProfile = newVolume > 0 ? "general" : "silent"
  91.  
  92.             // in silent mode, avoid changing general profile level if decrease is requested
  93.             if (profile !== "silent" || newProfile !== "silent") {
  94.                 ringerVolume = newVolume
  95.             }
  96.  
  97.             if (newProfile != profile) {
  98.                 profile = newProfile
  99.                 if (newProfile === "silent") {
  100.                     silenceVibra.start()
  101.                 }
  102.             }
  103.         }
  104.     }
  105.  
  106.     ConfigurationValue {
  107.         id: forceMediaVolume
  108.         key: "/jolla/sound/force_mediavolume"
  109.         defaultValue: false
  110.     }
  111.  
  112.     HapticsEffect {
  113.         id: silenceVibra
  114.         intensity: 0.2
  115.         duration: 85
  116.     }
  117.  
  118.     Item {
  119.         id: volumeArea
  120.  
  121.         width: parent.width
  122.         height: Theme.iconSizeSmall + Theme.paddingMedium
  123.         y: -height
  124.  
  125.         Rectangle {
  126.             anchors.fill: parent
  127.             color: Theme.overlayBackgroundColor
  128.             opacity: Theme.opacityOverlay
  129.         }
  130.  
  131.         Rectangle {
  132.             id: volumeRect
  133.  
  134.             objectName: "volumeRect"
  135.  
  136.             // On large screens display continuous volume changes
  137.             property real displayVolume: {
  138.                 if (!controllingMedia && profileControl.profile == "silent") {
  139.                     return 0
  140.                 }
  141.                 if (controllingMedia && volumeControl.callActive) {
  142.                     if (showContinuousVolume)
  143.                         return (continuousVolume+1) / (maximumVolume+1)
  144.                     else
  145.                         return (volumeControl.volume+1) / (volumeControl.maximumVolume+1)
  146.                 } else {
  147.                     if (showContinuousVolume)
  148.                         return continuousVolume / maximumVolume
  149.                     else if (controllingMedia)
  150.                         return volumeControl.volume / volumeControl.maximumVolume
  151.                     else
  152.                         return profileControl.ringerVolume / 100
  153.                 }
  154.             }
  155.  
  156.             property real widthFraction: displayVolume
  157.  
  158.             anchors {
  159.                 top: parent.top
  160.                 topMargin: Theme.paddingSmall/2
  161.                 bottom: parent.bottom
  162.                 bottomMargin: Theme.paddingSmall/2
  163.                 left: parent.left
  164.             }
  165.  
  166.             width: volumeArea.width * widthFraction
  167.  
  168.             Behavior on widthFraction {
  169.                 enabled: !showContinuousVolume && !disableSmoothChange
  170.                 NumberAnimation { easing.type: Easing.OutSine }
  171.             }
  172.  
  173.             color: _backgroundColor
  174.         }
  175.  
  176.         Item {
  177.             objectName: "volumeAnnotation"
  178.  
  179.             anchors.fill: parent
  180.  
  181.             property bool mute: controllingMedia
  182.                                 ? (!volumeControl.callActive && volumeControl.volume === 0)
  183.                                 : (profileControl.profile === "silent" || profileControl.ringerVolume === 0)
  184.             property real muteOpacity: mute ? 1 : 0
  185.             Behavior on muteOpacity {
  186.                 enabled: volumeBar.state != "" && volumeBar.state != "showBarExternal"
  187.                 FadeAnimation { property: "muteOpacity" }
  188.             }
  189.  
  190.             Image {
  191.                 id: muteIcon
  192.  
  193.                 anchors.verticalCenter: parent.verticalCenter
  194.                 x: Theme.horizontalPageMargin
  195.                 opacity: parent.muteOpacity
  196.  
  197.                 property string baseSource: controllingMedia ? "image://theme/icon-system-volume-mute" : "image://theme/icon-system-ringtone-mute"
  198.                 source: baseSource + "?" + _foregroundColor
  199.             }
  200.  
  201.             Image {
  202.                 id: volumeIcon
  203.  
  204.                 anchors.verticalCenter: parent.verticalCenter
  205.                 x: Theme.horizontalPageMargin
  206.                 opacity: 1 - parent.muteOpacity
  207.  
  208.                 property string baseSource: controllingMedia ? "image://theme/icon-system-volume" : "image://theme/icon-system-ringtone"
  209.                 source: baseSource + "?" + _foregroundColor
  210.             }
  211.  
  212.             Label {
  213.                 anchors {
  214.                     verticalCenter: parent.verticalCenter
  215.                     left: muteIcon.right
  216.                     leftMargin: Theme.paddingMedium
  217.                 }
  218.  
  219.                 font.pixelSize: Theme.fontSizeExtraSmall
  220.                 opacity: parent.muteOpacity
  221.                 color: _foregroundColor
  222.  
  223.                 //% "Muted"
  224.                 text: qsTrId("lipstick-jolla-home-la-muted")
  225.             }
  226.  
  227.             Label {
  228.                 anchors {
  229.                     verticalCenter: parent.verticalCenter
  230.                     left: volumeIcon.right
  231.                     leftMargin: Theme.paddingMedium
  232.                 }
  233.  
  234.                 font.pixelSize: Theme.fontSizeExtraSmall
  235.                 opacity: 1 - parent.muteOpacity
  236.                 color: _foregroundColor
  237.  
  238.                 text: {
  239.                     if (controllingMedia) {
  240.                         if (volumeControl.volume > volumeControl.safeVolume) {
  241.                             //% "High volume"
  242.                             return qsTrId("lipstick-jolla-home-la-high-volume")
  243.                         } else if (volumeControl.callActive && volumeControl.volume === 0) {
  244.                             //: Label used when minimum (unmuted) volume is set
  245.                             //% "Minimum"
  246.                             return qsTrId("lipstick-jolla-home-la-minimum-volume")
  247.                         } else {
  248.                             //% "Volume"
  249.                             return qsTrId("lipstick-jolla-home-la-volume")
  250.                         }
  251.                     } else {
  252.                         //% "Ringtone volume"
  253.                         return qsTrId("lipstick-jolla-home-la-ringtone_volume")
  254.                     }
  255.                 }
  256.             }
  257.         }
  258.     }
  259.  
  260.     states: [
  261.         State {
  262.             name: "showBar"
  263.             PropertyChanges {
  264.                 target: volumeArea
  265.                 y: 0
  266.             }
  267.         },
  268.         State {
  269.             name: "showBarKey"
  270.             extend: "showBar"
  271.             PropertyChanges {
  272.                 target: volumeBar
  273.                 disableSmoothChange: false
  274.             }
  275.             PropertyChanges {
  276.                 target: volumeRect
  277.                 widthFraction: volumeRect.displayVolume
  278.             }
  279.         },
  280.         State {
  281.             name: "showBarGesture"
  282.             extend: "showBar"
  283.             PropertyChanges {
  284.                 target: volumeBar
  285.                 showContinuousVolume: Screen.sizeCategory >= Screen.Large
  286.             }
  287.         },
  288.         State {
  289.             name: "showBarExternal"
  290.             extend: "showBar"
  291.             PropertyChanges {
  292.                 target: volumeBar
  293.                 controllingMedia: false
  294.                 showContinuousVolume: false
  295.             }
  296.         }
  297.     ]
  298.  
  299.     transitions: [
  300.         Transition {
  301.             from: ""
  302.             to: "showBarKey"
  303.             SequentialAnimation {
  304.                 ScriptAction {
  305.                     script: {
  306.                         volumeRect.widthFraction = volumeRect.displayVolume + initialChange
  307.                     }
  308.                 }
  309.                 NumberAnimation {
  310.                     target: volumeArea
  311.                     property: "y"
  312.                     duration: 200
  313.                     easing.type: Easing.OutQuad
  314.                 }
  315.                 NumberAnimation {
  316.                     target: volumeRect
  317.                     property: "widthFraction"
  318.                     easing.type: Easing.OutSine
  319.                 }
  320.                 PropertyAction {
  321.                     target: volumeBar
  322.                     property: "disableSmoothChange"
  323.                 }
  324.                 ScriptAction { script: hideTimer.restart() }
  325.             }
  326.         },
  327.         Transition {
  328.             from: ""
  329.             to: "showBarGesture"
  330.             SequentialAnimation {
  331.                 PropertyAction {
  332.                     target: volumeBar
  333.                     property: "showContinuousVolume"
  334.                 }
  335.                 NumberAnimation {
  336.                     target: volumeArea
  337.                     property: "y"
  338.                     duration: 200
  339.                     easing.type: Easing.OutQuad
  340.                 }
  341.                 ScriptAction { script: hideTimer.restart() }
  342.             }
  343.         },
  344.         Transition {
  345.             from: ""
  346.             to: "showBarExternal"
  347.             SequentialAnimation {
  348.                 PauseAnimation {
  349.                     duration: 150
  350.                 }
  351.                 NumberAnimation {
  352.                     target: volumeArea
  353.                     property: "y"
  354.                     duration: 300
  355.                     easing.type: Easing.InOutQuad
  356.                 }
  357.                 ScriptAction { script: hideTimer.restart() }
  358.             }
  359.         },
  360.         Transition {
  361.             to: ""
  362.             SequentialAnimation {
  363.                 NumberAnimation {
  364.                     target: volumeArea
  365.                     property: "y"
  366.                     duration: 200
  367.                     easing.type: Easing.OutQuad
  368.                 }
  369.                 PropertyAction {
  370.                     target: volumeBar
  371.                     properties: "disableSmoothChange, showContinuousVolume"
  372.                 }
  373.                 PropertyAction {
  374.                     target: volumeRect
  375.                     property: "widthFraction"
  376.                 }
  377.                 ScriptAction {
  378.                     script: {
  379.                         volumeControl.windowVisible = false
  380.                         loader.warningActive = false
  381.                         if (lateScreenshotCapture) {
  382.                             if (!screenshot) {
  383.                                 var component = Qt.createComponent(Qt.resolvedUrl("Screenshot.qml"))
  384.                                 if (component.status == Component.Ready) {
  385.                                     screenshot = component.createObject(volumeBar)
  386.                                 } else {
  387.                                     console.warn("Screenshot object instantiation failed:", component.errorString())
  388.                                 }
  389.                             }
  390.                             if (screenshot) {
  391.                                 screenshot.capture()
  392.                             }
  393.                         }
  394.                         lateScreenshotCapture = false
  395.                     }
  396.                 }
  397.             }
  398.         }
  399.     ]
  400.  
  401.     Loader {
  402.         id: loader
  403.  
  404.         property bool warningActive
  405.  
  406.         function showWarning(initial) {
  407.             warningActive = true
  408.             loader.item.initial = initial
  409.             loader.item.dismiss.connect(function () {
  410.                 opacity = 0.0
  411.                 warningActive = false
  412.                 hideTimer.restart()
  413.             })
  414.             hideTimer.stop()
  415.             opacity = 1.0
  416.         }
  417.  
  418.         source: "WarningNote.qml"
  419.         active: warningActive || warningFade.running
  420.         opacity: 0.0
  421.  
  422.         anchors {
  423.             top: volumeArea.bottom
  424.             bottom: parent.bottom
  425.             left: parent.left
  426.             right: parent.right
  427.         }
  428.  
  429.         Behavior on opacity { FadeAnimator { id: warningFade; duration: 300  } }
  430.     }
  431.  
  432.     Timer {
  433.         id: hideTimer
  434.         interval: 1500
  435.         onTriggered: {
  436.             if (!Lipstick.compositor.volumeGestureFilterItem.active)
  437.                 volumeBar.state = ""
  438.         }
  439.     }
  440.  
  441.     Timer {
  442.         id: keyRepeatDelay
  443.         interval: 600
  444.         onTriggered: keyRepeat.start()
  445.     }
  446.  
  447.     Timer {
  448.         id: keyRepeat
  449.         interval: volumeBar.controllingMedia ? 75 : 300
  450.         repeat: true
  451.         onTriggered: {
  452.             if (volumeBar.controllingMedia) {
  453.                 if (volumeIncreasing) {
  454.                     mprisManager.previous()
  455.                     initialChange = volumeControl.volume === volumeControl.maximumVolume ? 0 : -1 / (volumeControl.maximumVolume+1)  }
  456.                 else {
  457.                     mprisManager.next()
  458.                     initialChange = volumeControl.volume === 0 ? 0 : 1 / (volumeControl.maximumVolume+1) }
  459.                 keyRepeat.stop()
  460.                 keyRepeatDelay.stop()
  461.                 volumeControl.volume = volumeControl.volume - (volumeBar.volumeIncreasing ? 1 : -1)
  462.             } else {
  463.                 profileControl.adjustRingtoneVolume(volumeBar.volumeIncreasing ? 20 : -20)
  464.             }
  465.  
  466.             restartHideTimerIfWindowVisibleAndWarningNotVisible()
  467.         }
  468.     }
  469.  
  470.     Connections {
  471.         target: volumeControl
  472.         onWindowVisibleChanged: {
  473.             if (volumeControl.windowVisible) {
  474.                 if (volumeBar.state == "") {
  475.                     if (Lipstick.compositor.volumeGestureFilterItem.active) {
  476.                         volumeBar.state = "showBarGesture"
  477.                     } else {
  478.                         volumeBar.state = "showBarKey"
  479.                         hideTimer.restart()
  480.                     }
  481.                 }
  482.             }
  483.         }
  484.         onVolumeChanged: restartHideTimerIfWindowVisibleAndWarningNotVisible()
  485.         onVolumeKeyPressed: {
  486.             if (keyRepeat.running || keyRepeatDelay.running) {
  487.                 if (Lipstick.compositor.visible) {
  488.                     screenshotTimer.restart()
  489.                 }
  490.                 return
  491.             }
  492.  
  493.             volumeBar.volumeIncreasing = (key == Qt.Key_VolumeUp)
  494.  
  495.             if (volumeBar.controllingMedia) {
  496.                 initialChange = 0
  497.                 baseVolume = volumeControl.volume
  498.                 keyRepeat.stop()
  499.                 keyRepeatDelay.restart()
  500.             } else {
  501.                 if (volumeControl.windowVisible) {
  502.                     if (volumeIncreasing)
  503.                         initialChange = profileControl.ringerVolume === 100 ? 0 : -0.2
  504.                     else
  505.                         initialChange = profileControl.ringerVolume === 0 ? 0 : 0.2
  506.  
  507.                     profileControl.adjustRingtoneVolume(volumeBar.volumeIncreasing ? 20 : -20)
  508.                 } else {
  509.                     initialChange = 0
  510.                 }
  511.  
  512.                 keyRepeat.restart() // no initial delay
  513.             }
  514.  
  515.             volumeBar.state = "showBarKey"
  516.             volumeControl.windowVisible = true
  517.             restartHideTimerIfWindowVisibleAndWarningNotVisible()
  518.         }
  519.         onVolumeKeyReleased: {
  520.             initialChange = 0
  521.             if (volumeBar.controllingMedia)
  522.                 keyRepeat.stop()
  523.                 keyRepeatDelay.stop()
  524.                 if (volumeIncreasing)
  525.                     initialChange = volumeControl.volume === volumeControl.maximumVolume ? 0 : -1 / (volumeControl.maximumVolume+1)
  526.                 else
  527.                     initialChange = volumeControl.volume === 0 ? 0 : 1 / (volumeControl.maximumVolume+1)
  528.                 volumeControl.volume = volumeControl.volume + (volumeBar.volumeIncreasing ? 1 : -1)          
  529.             if (volumeBar.volumeIncreasing == (key == Qt.Key_VolumeUp)) {
  530.                 // Handle pressing both buttons and releasing the first, though
  531.                 // in that case keyRepeat is probably already stopped by screenshotTimer
  532.                 keyRepeat.stop()
  533.                 keyRepeatDelay.stop()
  534.             }
  535.             screenshotTimer.stop()
  536.             lateScreenshotCapture = false
  537.         }
  538.         onShowAudioWarning: loader.showWarning(initial)
  539.     }
  540.  
  541.     Connections {
  542.         target: Lipstick.compositor.volumeGestureFilterItem
  543.         onActiveChanged: {
  544.             if (Lipstick.compositor.volumeGestureFilterItem.active) {
  545.                 if (!volumeControl.windowVisible)
  546.                     baseVolume = continuousVolume
  547.                 volumeBar.state = "showBarGesture"
  548.                 volumeControl.windowVisible = true
  549.                 hideTimer.stop()
  550.             } else {
  551.                 baseVolume = continuousVolume
  552.                 restartHideTimerIfWindowVisibleAndWarningNotVisible()
  553.             }
  554.         }
  555.     }
  556.  
  557.     Connections {
  558.         target: Desktop
  559.         onShowVolumeBar: {
  560.             volumeBar.state = "showBarExternal"
  561.             volumeControl.windowVisible = true
  562.             restartHideTimerIfWindowVisibleAndWarningNotVisible()
  563.         }
  564.     }
  565.  
  566.     Timer {
  567.         id: screenshotTimer
  568.         interval: 200
  569.         onTriggered: {
  570.             lateScreenshotCapture = true
  571.             keyRepeat.stop()
  572.             keyRepeatDelay.stop()
  573.             initialChange = 0
  574.             if (volumeBar.controllingMedia)
  575.                 baseVolume = volumeControl.volume
  576.             volumeBar.volumeIncreasing = false
  577.             volumeBar.state = ""
  578.         }
  579.     }
  580.  
  581.     function restartHideTimerIfWindowVisibleAndWarningNotVisible() {
  582.         if (volumeControl.windowVisible && !loader.warningActive && !Lipstick.compositor.volumeGestureFilterItem.active) {
  583.             hideTimer.restart()
  584.         }
  585.     }
  586. }
  587.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement