Add support for the keypad interface in media devices

This commit is contained in:
Michael Zanetti 2019-07-20 16:20:46 +02:00
parent b5a0fcd650
commit a2f1fa93b2
14 changed files with 554 additions and 45 deletions

View File

@ -407,14 +407,8 @@ void NymeaConnection::updateActiveBearers()
qDebug() << "Inactive network config:" << config.name() << config.bearerTypeFamily() << config.bearerTypeName();
}
// Retrying with a new config manager:
QNetworkConfigurationManager *newMan = new QNetworkConfigurationManager(this);
qDebug() << "Trying with new config manager:";
configs = newMan->allConfigurations();
foreach (const QNetworkConfiguration &config, configs) {
qDebug() << "Config:" << config.name() << config.bearerTypeFamily() << config.bearerTypeName() << config.state();
}
newMan->deleteLater();
qWarning() << "Updating network manager";
m_networkConfigManager->updateConfigurations();
}
if (m_availableBearerTypes != availableBearerTypes) {

View File

@ -474,7 +474,7 @@ BrowserItem *DeviceManager::browserItem(const QUuid &deviceId, const QString &it
void DeviceManager::browseDeviceResponse(const QVariantMap &params)
{
qDebug() << "Browsing response:" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson(QJsonDocument::Indented));
// qDebug() << "Browsing response:" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson(QJsonDocument::Indented));
int id = params.value("id").toInt();
if (!m_browsingRequests.contains(id)) {
qWarning() << "Received a browsing reply for an id we don't know.";

View File

@ -208,5 +208,6 @@
<file>ui/images/browser/BrowserIconApplication.svg</file>
<file>ui/images/browser/BrowserIconDocument.svg</file>
<file>ui/images/browser/BrowserIconPackage.svg</file>
<file>ui/images/home.svg</file>
</qresource>
</RCC>

View File

@ -191,5 +191,7 @@
<file>ui/components/BrowserContextMenu.qml</file>
<file>ui/magic/SelectBrowserItemActionPage.qml</file>
<file>ui/delegates/BrowserItemDelegate.qml</file>
<file>ui/components/NavigationPad.qml</file>
<file>ui/components/KeypadButton.qml</file>
</qresource>
</RCC>

View File

@ -10,7 +10,7 @@ ApplicationWindow {
font.capitalization: Font.MixedCase
font.family: "Ubuntu"
Material.background: "black"
Material.background: "#151515"
// The core system name.
property string systemName: "nymea"

View File

@ -25,7 +25,7 @@ T.Button {
contentItem: Text {
text: control.text
color: app.backgroundColor
color: control.Material.backgroundColor
font.bold: control.font.bold
font.capitalization: Font.AllUppercase
font.family: control.font.family

View File

@ -0,0 +1,32 @@
import QtQuick 2.5
import Nymea 1.0
import QtQuick.Controls 2.2
import QtQuick.Controls.Material 2.2
import QtQuick.Layouts 1.3
Item {
id: root
property alias imageSource: icon.name
property color activeColor: app.accentColor
function activate() {
t.start();
}
ColorIcon {
id: icon
anchors.fill: parent
color: active ? root.activeColor : keyColor
Behavior on color { ColorAnimation { duration: 200 } }
property bool active: t.running
Timer {
id: t;
interval: 200
}
}
}

View File

@ -0,0 +1,255 @@
import QtQuick 2.5
import Nymea 1.0
import QtQuick.Controls 2.2
import QtQuick.Controls.Material 2.2
import QtQuick.Layouts 1.3
Item {
id: root
property Device device: null
readonly property bool isExtended: device && device.deviceClass.interfaces.indexOf("extendednavigationpad") >= 0
readonly property ActionType navigateActionType: device ? device.deviceClass.actionTypes.findByName("navigate") : null
Pane {
id: pane
Material.elevation: 2
width: Math.min(root.width, root.height)
height: Math.min(root.width, root.height)
anchors.centerIn: parent
padding: 0
contentItem: Item {
Pane {
anchors.centerIn: parent
Material.elevation: 2
rotation: 45
width: Math.sqrt(Math.pow(parent.width / 2, 2) + Math.pow(parent.height / 2, 2))
height: width
}
KeypadButton {
id: backButton
anchors { left: parent.left; top: parent.top; margins: parent.width * .1 }
height: app.iconSize
width: app.iconSize
imageSource: "../images/back.svg"
Item { id: backButtonArea; anchors.centerIn: parent; width: pane.width / 4; height: width; rotation: 45; }
}
KeypadButton {
id: menuButton
anchors { right: parent.right; top: parent.top; margins: parent.width * .1 }
height: app.iconSize
width: app.iconSize
visible: root.device.deviceClass.interfaces.indexOf("extendednavigationpad") >= 0
imageSource: "../images/navigation-menu.svg"
Item { id: menuButtonArea; anchors.centerIn: parent; width: pane.width / 4; height: width; rotation: 45 }
}
KeypadButton {
id: homeButton
anchors { left: parent.left; bottom: parent.bottom; margins: parent.width * .1 }
height: app.iconSize
width: app.iconSize
imageSource: "../images/home.svg"
visible: root.device.deviceClass.interfaces.indexOf("extendednavigationpad") >= 0
Item { id: homeButtonArea; anchors.centerIn: parent; width: pane.width / 4; height: width; rotation: 45 }
}
KeypadButton {
id: infoButton
anchors { right: parent.right; bottom: parent.bottom; margins: parent.width * .1 }
height: app.iconSize
width: app.iconSize
imageSource: "../images/info.svg"
visible: root.device.deviceClass.interfaces.indexOf("extendednavigationpad") >= 0
Item { id: infoButtonArea; anchors.centerIn: parent; width: pane.width / 4; height: width; rotation: 45 }
}
Rectangle {
id: enterButton
anchors.centerIn: parent
height: app.iconSize
width: app.iconSize
radius: width / 2
border.color: t.running ? app.accentColor : "#808080"
Behavior on border.color { ColorAnimation { duration: 200 } }
Timer { id: t; interval: 400 }
border.width: 3
color: "transparent"
function activate() { t.start() }
}
Item { id: enterButtonArea; anchors.centerIn: parent; width: pane.width / 4; height: width; rotation: 0 }
Item { id: leftButtonArea; anchors { left: parent.left; verticalCenter: parent.verticalCenter; } width: pane.width / 4; height: width; rotation: 0 }
Item { id: rightButtonArea; anchors { right: parent.right; verticalCenter: parent.verticalCenter; } width: pane.width / 4; height: width; rotation: 0 }
Item { id: upButtonArea; anchors { top: parent.top; horizontalCenter: parent.horizontalCenter; } width: pane.width / 4; height: width; rotation: 0 }
Item { id: downButtonArea; anchors { bottom: parent.bottom; horizontalCenter: parent.horizontalCenter; } width: pane.width / 4; height: width; rotation: 0 }
Repeater {
id: directionsRepeater
model: 4
Column {
height: parent.height * .8
width: app.iconSize
anchors.centerIn: parent
rotation: index * 90
function activate() {
if (!delayTimer.running) {
delayTimer.idx = 2;
delayTimer.start();
} else {
delayTimer.onceMore = true;
}
}
Timer {
id: delayTimer;
triggeredOnStart: true
interval: 150
repeat: true
property int idx: 2
property bool onceMore: false
onTriggered: {
print("activating", idx)
childRepeater.itemAt(idx--).activate()
if (idx < 0) {
if (onceMore) {
idx = 2;
onceMore = false;
} else {
delayTimer.stop();
}
}
}
}
Repeater {
id: childRepeater
model: 3
KeypadButton {
height: app.iconSize
width: height
imageSource: "../images/up.svg"
}
}
}
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
preventStealing: true
property int startX
property int startY
property string lockedDirection: "none"
readonly property int steps: 20
readonly property int stepSize: height / steps
property int horizontalSteps: 0
property int verticalSteps: 0
onPressed: {
startX = mouseX
startY = mouseY
}
onPositionChanged: {
var horizontalDiff = mouseX - startX
var verticalDiff = mouseY - startY
if (lockedDirection == "none") {
if (Math.abs(horizontalDiff) > stepSize) {
lockedDirection = "horizontal"
trigger(horizontalDiff > 0 ? "right" : "left")
directionsRepeater.itemAt(horizontalDiff > 0 ? 1 : 2).activate()
} else if (Math.abs(verticalDiff) > stepSize) {
lockedDirection = "vertical"
trigger(verticalDiff > 0 ? "down" : "up")
directionsRepeater.itemAt(verticalDiff > 0 ? 2 : 0).activate()
}
}
horizontalSteps = horizontalDiff / stepSize
verticalSteps = verticalDiff / stepSize
}
onReleased: {
if (lockedDirection === "none") {
if (checkButton(backButtonArea)) {
trigger("back");
backButton.activate();
} else if (checkButton(leftButtonArea)) {
trigger("left");
directionsRepeater.itemAt(3).activate()
} else if (checkButton(rightButtonArea)) {
trigger("right");
directionsRepeater.itemAt(1).activate()
} else if (checkButton(upButtonArea)) {
trigger("up");
directionsRepeater.itemAt(0).activate()
} else if (checkButton(downButtonArea)) {
trigger("down");
directionsRepeater.itemAt(2).activate()
} else if (checkButton(enterButtonArea)) {
trigger("enter");
enterButton.activate();
} else if (checkButton(menuButtonArea)) {
trigger("menu");
menuButton.activate();
} else if (checkButton(homeButtonArea)) {
trigger("home");
homeButton.activate();
} else if (checkButton(infoButtonArea)) {
trigger("info");
infoButton.activate();
}
}
lockedDirection = "none"
}
function checkButton(button) {
var coords = mouseArea.mapToItem(button, mouseX, mouseY)
if (coords.x > 0 && coords.x < button.width && coords.y > 0 && coords.y < button.height) {
return true;
}
return false;
}
function trigger(direction) {
var params = []
var param = {}
param["paramTypeId"] = root.navigateActionType.paramTypes.findByName("to").id;
param["value"] = direction;
params.push(param);
engine.deviceManager.executeAction(root.device.id, root.navigateActionType.id, params)
PlatformHelper.vibrate(PlatformHelper.HapticsFeedbackSelection)
}
Timer {
id: repeatTimer
running: mouseArea.lockedDirection !== "none"
interval: 1000
repeat: true
onRunningChanged: interval = 1000
onTriggered: {
if (mouseArea.lockedDirection === "horizontal") {
mouseArea.trigger(mouseArea.horizontalSteps > 0 ? "right" : "left")
directionsRepeater.itemAt(mouseArea.horizontalSteps > 0 ? 1 : 3).activate()
} else if (mouseArea.lockedDirection === "vertical") {
mouseArea.trigger(mouseArea.verticalSteps > 0 ? "down" : "up")
directionsRepeater.itemAt(mouseArea.verticalSteps > 0 ? 2 : 0).activate()
}
interval = Math.max(50, 1000 - Math.abs(mouseArea.lockedDirection === "horizontal" ? mouseArea.horizontalSteps : mouseArea.verticalSteps) * 100)
}
}
}
}
}

View File

@ -15,7 +15,7 @@ SwipeDelegate {
property bool prominentSubText: true
property string iconName
property string fallbackIcon
property string thumbnail
property int iconSize: app.iconSize
property color iconColor: app.accentColor
property alias iconKeyColor: icon.keyColor
@ -41,21 +41,24 @@ SwipeDelegate {
Item {
Layout.preferredHeight: root.iconSize
Layout.preferredWidth: height
visible: root.iconName || root.fallbackIcon
visible: root.iconName.length > 0 || root.thumbnail.length > 0
ColorIcon {
id: icon
anchors.fill: parent
name: root.iconName
color: root.iconColor
visible: root.iconName
visible: root.iconName && thumbnailImage.status !== Image.Ready
}
ColorIcon {
Image {
id: thumbnailImage
anchors.fill: parent
name: root.fallbackIcon
color: root.iconColor
visible: root.fallbackIcon && (!root.iconName || icon.status === Image.Error)
source: root.thumbnail
visible: root.thumbnail.length > 0
fillMode: Image.PreserveAspectFit
horizontalAlignment: Image.AlignHCenter
verticalAlignment: Image.AlignVCenter
}
BusyIndicator {

View File

@ -12,8 +12,8 @@ NymeaListItemDelegate {
progressive: model.browsable
subText: model.description
prominentSubText: false
iconName: model.thumbnail
fallbackIcon: "../images/browser/" + model.icon + ".svg"
iconName: "../images/browser/" + model.icon + ".svg"
thumbnail: model.thumbnail
enabled: model.browsable || model.executable
secondaryIconName: model.actionTypeIds.length > 0 ? "../images/navigation-menu.svg" : ""
secondaryIconClickable: true

View File

@ -43,7 +43,7 @@ DeviceListPageBase {
readonly property StateType playerTypeStateType: deviceClass.stateTypes.findByName("playerType")
readonly property State playerTypeState: playerTypeStateType ? device.states.getState(playerTypeStateType.id) : null
bottomPadding: index === ListView.view.count - 1 ? topPadding : 0
bottomPadding: index === root.devicesProxy.count - 1 ? topPadding : 0
contentItem: Pane {
id: contentItem
Material.elevation: 2
@ -96,7 +96,7 @@ DeviceListPageBase {
qsTr("No playback")
: itemDelegate.device.states.getState(itemDelegate.deviceClass.stateTypes.findByName("title").id).value
horizontalAlignment: Text.AlignHCenter
// font.pixelSize: app.largeFont
// font.pixelSize: app.largeFont
elide: Text.ElideRight
}
Label {
@ -193,10 +193,8 @@ DeviceListPageBase {
}
}
}
}
}
}
}
}
}

View File

@ -14,15 +14,7 @@ DevicePageBase {
showBrowserButton: false
onBackPressed: {
if (swipeView.currentIndex > 0) {
if (internalPageStack.depth > 1) {
internalPageStack.pop();
} else {
swipeView.currentIndex = 0;
}
} else {
pageStack.pop();
}
swipeView.currentItem.backPressed()
}
Component.onCompleted: {
@ -83,9 +75,22 @@ DevicePageBase {
SwipeView {
id: swipeView
anchors.fill: parent
interactive: root.deviceClass.browsable
Component.onCompleted: {
if (root.deviceClass.browsable) {
browserComponent.createObject(swipeView)
}
if (root.deviceClass.interfaces.indexOf("navigationpad") >= 0) {
navigationComponent.createObject(swipeView)
}
}
Item {
function backPressed() {
pageStack.pop();
}
GridLayout {
id: contentColumn
anchors.fill: parent
@ -139,8 +144,21 @@ DevicePageBase {
}
}
}
Component {
id: browserComponent
Item {
function backPressed() {
if (internalPageStack.depth > 1) {
internalPageStack.pop();
} else {
swipeView.currentIndex--
}
}
StackView {
id: internalPageStack
anchors.fill: parent
@ -150,7 +168,6 @@ DevicePageBase {
id: internalBrowserPage
ListView {
id: listView
anchors.fill: parent
model: browserItems
ScrollBar.vertical: ScrollBar {}
@ -163,7 +180,7 @@ DevicePageBase {
}
delegate: BrowserItemDelegate {
fallbackIcon: "../images/browser/" + (model.mediaIcon && model.mediaIcon !== "MediaBrowserIconNone" ? model.mediaIcon : model.icon) + ".svg"
iconName: "../images/browser/" + (model.mediaIcon && model.mediaIcon !== "MediaBrowserIconNone" ? model.mediaIcon : model.icon) + ".svg"
busy: d.pendingItemId === model.id
device: root.device
@ -188,10 +205,34 @@ DevicePageBase {
}
}
}
}
}
}
Component {
id: navigationComponent
Item {
function backPressed() {
swipeView.currentIndex--;
}
ColumnLayout {
anchors.fill: parent
anchors.margins: app.margins
NavigationPad {
Layout.fillWidth: true
Layout.fillHeight: true
device: root.device
}
MediaControls {
Layout.fillWidth: true
device: root.device
}
}
}
}
@ -246,10 +287,10 @@ DevicePageBase {
Item {
Layout.fillWidth: true
Layout.preferredHeight: 2
visible: root.deviceClass.browsable
visible: swipeView.count > 1
Rectangle {
height: parent.height
width: parent.width / 2
width: parent.width / swipeView.count
color: app.accentColor
x: swipeView.currentIndex * width
Behavior on x { NumberAnimation { duration: 150 } }
@ -259,14 +300,14 @@ DevicePageBase {
RowLayout {
Item {
Layout.fillHeight: true
Layout.preferredWidth: root.deviceClass.browsable && swipeView.currentIndex > 0 ? parent.width / 4 : 0
Layout.preferredWidth: swipeView.count > 1 && swipeView.currentIndex > 0 ? parent.width / 4 : 0
Behavior on Layout.preferredWidth { NumberAnimation {} }
HeaderButton {
anchors.centerIn: parent
imageSource: "../images/back.svg"
opacity: root.deviceClass.browsable && swipeView.currentIndex == 1 ? 1 : 0
opacity: swipeView.count > 1 && swipeView.currentIndex > 0 ? 1 : 0
Behavior on opacity { NumberAnimation {} }
onClicked: swipeView.currentIndex = 0
onClicked: swipeView.currentIndex--
}
}
Item {
@ -329,13 +370,13 @@ DevicePageBase {
}
Item {
Layout.fillHeight: true
Layout.preferredWidth: root.deviceClass.browsable && swipeView.currentIndex == 0 ? parent.width / 4 : 0
Layout.preferredWidth: swipeView.count > 1 && swipeView.currentIndex < swipeView.count - 1 ? parent.width / 4 : 0
Behavior on Layout.preferredWidth { NumberAnimation {} }
HeaderButton {
anchors.centerIn: parent
imageSource: "../images/next.svg"
onClicked: swipeView.currentIndex = 1
opacity: root.deviceClass.browsable && swipeView.currentIndex == 0 ? 1 : 0
onClicked: swipeView.currentIndex++
opacity: swipeView.count > 1 && swipeView.currentIndex < swipeView.count - 1 ? 1 : 0
Behavior on opacity { NumberAnimation {} }
}
}

View File

@ -0,0 +1,177 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="96"
height="96"
id="svg4874"
version="1.1"
inkscape:version="0.91+devel r"
viewBox="0 0 96 96.000001"
sodipodi:docname="home.svg">
<defs
id="defs4876" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="3.5967995"
inkscape:cx="-22.603439"
inkscape:cy="10.133975"
inkscape:document-units="px"
inkscape:current-layer="g4780"
showgrid="true"
showborder="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:object-paths="true"
inkscape:snap-intersection-paths="true"
inkscape:object-nodes="true"
inkscape:snap-smooth-nodes="true"
inkscape:snap-midpoints="true"
inkscape:snap-object-midpoints="true"
inkscape:snap-center="true"
showguides="true"
inkscape:guide-bbox="true"
inkscape:snap-global="true">
<inkscape:grid
type="xygrid"
id="grid5451"
empspacing="8" />
<sodipodi:guide
orientation="1,0"
position="8,-8.0000001"
id="guide4063" />
<sodipodi:guide
orientation="1,0"
position="4,-8.0000001"
id="guide4065" />
<sodipodi:guide
orientation="0,1"
position="-8,88.000001"
id="guide4067" />
<sodipodi:guide
orientation="0,1"
position="-8,92.000001"
id="guide4069" />
<sodipodi:guide
orientation="0,1"
position="104,4"
id="guide4071" />
<sodipodi:guide
orientation="0,1"
position="-5,8.0000001"
id="guide4073" />
<sodipodi:guide
orientation="1,0"
position="88,-8.0000001"
id="guide4077" />
<sodipodi:guide
orientation="0,1"
position="-8,84.000001"
id="guide4074" />
<sodipodi:guide
orientation="1,0"
position="12,-8.0000001"
id="guide4076" />
<sodipodi:guide
orientation="1,0"
position="84,-8.0000001"
id="guide4080" />
<sodipodi:guide
position="-8,48"
orientation="0,1"
id="guide4172" />
<sodipodi:guide
position="92,-8.0000001"
orientation="1,0"
id="guide4760" />
</sodipodi:namedview>
<metadata
id="metadata4879">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(67.857146,-78.50504)">
<g
transform="matrix(0,-1,-1,0,373.50506,516.50504)"
id="g4845"
style="display:inline">
<g
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="next01.png"
transform="matrix(-0.9996045,0,0,1,575.94296,-611.00001)"
id="g4778"
inkscape:label="Layer 1">
<g
transform="matrix(-1,0,0,1,575.99999,611)"
id="g4780"
style="display:inline">
<rect
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:none;stroke-width:4;marker:none;enable-background:accumulate"
id="rect4782"
width="96.037987"
height="96"
x="-438.00244"
y="345.36221"
transform="scale(-1,1)" />
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="path4667"
d="m 405.98979,361.35146 12.00475,0 0,12.01076 z"
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:48;marker:none;enable-background:accumulate"
inkscape:transform-center-x="-26.000146"
inkscape:transform-center-y="-19.865735" />
<path
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;line-height:125%;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;display:inline;fill:#808080;fill-opacity:1;stroke:none"
d="m 15.988281,39 0,49 L 68,88 l 4e-6,-4.000006 -48,0 0,-45.999998 z m 60.011723,-1.000004 0,49.999998 4.011715,6e-6 -0.01171,-50.000004 z"
transform="matrix(0,-1,-1.0003957,0,438.00245,441.36222)"
id="path4658"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccc" />
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:none;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.00079107;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 389.38086,349.93164 -2.79492,2.86133 41.55078,40.57031 -41.55078,40.56836 2.79492,2.86133 44.48242,-43.43164 -44.48242,-43.42969 z"
id="path4158"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4165"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#808080;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 384.74345,393.36217 c 0.2538,-1.01585 0.5239,-2.36509 0.80985,-4.04761 0.28572,-1.68252 0.42858,-3.61904 0.42858,-5.80952 0,-1.96822 -0.28571,-3.60317 -0.85748,-4.90475 -0.5399,-1.30156 -1.318,-2.33332 -2.33429,-3.09522 -0.98451,-0.79367 -2.17546,-1.34919 -3.57285,-1.66667 -1.39737,-0.31762 -2.93765,-0.47618 -4.62083,-0.47618 l -24.62884,0 1.9e-4,20 z"
sodipodi:nodetypes="ccsccssccc" />
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@ -26,6 +26,12 @@ Page {
anchors.fill: parent
ScrollBar.vertical: ScrollBar {}
BusyIndicator {
anchors.centerIn: parent
running: listView.model.busy
visible: running
}
delegate: BrowserItemDelegate {
width: parent.width
device: root.device