1
0
Fork 0

Grid-view for the launcher

This commit is contained in:
James Turner 2018-11-07 09:23:17 +01:00
parent df810f7970
commit 0239d5ef44
13 changed files with 462 additions and 121 deletions

View file

@ -106,6 +106,8 @@ LauncherController::LauncherController(QObject *parent, QWindow* window) :
LocalAircraftCache::instance()->scanDirs(); LocalAircraftCache::instance()->scanDirs();
m_aircraftModel->setPackageRoot(globals->packageRoot()); m_aircraftModel->setPackageRoot(globals->packageRoot());
m_aircraftGridMode = settings.value("aircraftGridMode").toBool();
m_subsystemIdleTimer = new QTimer(this); m_subsystemIdleTimer = new QTimer(this);
m_subsystemIdleTimer->setInterval(10); m_subsystemIdleTimer->setInterval(10);
connect(m_subsystemIdleTimer, &QTimer::timeout, []() connect(m_subsystemIdleTimer, &QTimer::timeout, []()
@ -821,13 +823,24 @@ void LauncherController::saveConfigAs()
m_config->saveConfigToFile(file); m_config->saveConfigToFile(file);
} }
void LauncherController::setAircraftGridMode(bool aircraftGridMode)
{
if (m_aircraftGridMode == aircraftGridMode)
return;
QSettings settings;
settings.setValue("aircraftGridMode", aircraftGridMode);
m_aircraftGridMode = aircraftGridMode;
emit aircraftGridModeChanged(m_aircraftGridMode);
}
void LauncherController::setMinWindowSize(QSize sz) void LauncherController::setMinWindowSize(QSize sz)
{ {
if (sz == m_minWindowSize) if (sz == m_minWindowSize)
return; return;
m_window->setMinimumSize(sz); m_window->setMinimumSize(sz);
emit minWindowSizeChanged(); emit minWindowSizeChanged();
} }
QUrl LauncherController::flyIconUrl() const QUrl LauncherController::flyIconUrl() const

View file

@ -86,6 +86,7 @@ class LauncherController : public QObject
Q_PROPERTY(QUrl flyIconUrl READ flyIconUrl NOTIFY selectedAircraftChanged) Q_PROPERTY(QUrl flyIconUrl READ flyIconUrl NOTIFY selectedAircraftChanged)
Q_PROPERTY(bool aircraftGridMode READ aircraftGridMode WRITE setAircraftGridMode NOTIFY aircraftGridModeChanged)
public: public:
explicit LauncherController(QObject *parent, QWindow* win); explicit LauncherController(QObject *parent, QWindow* win);
@ -187,6 +188,11 @@ public:
QUrl flyIconUrl() const; QUrl flyIconUrl() const;
bool aircraftGridMode() const
{
return m_aircraftGridMode;
}
signals: signals:
void selectedAircraftChanged(QUrl selectedAircraft); void selectedAircraftChanged(QUrl selectedAircraft);
@ -199,6 +205,8 @@ signals:
void viewCommandLine(); void viewCommandLine();
void aircraftGridModeChanged(bool aircraftGridMode);
public slots: public slots:
void setSelectedAircraft(QUrl selectedAircraft); void setSelectedAircraft(QUrl selectedAircraft);
@ -217,6 +225,8 @@ public slots:
void openConfig(); void openConfig();
void saveConfigAs(); void saveConfigAs();
void setAircraftGridMode(bool aircraftGridMode);
private slots: private slots:
void onAircraftInstalledCompleted(QModelIndex index); void onAircraftInstalledCompleted(QModelIndex index);
@ -271,6 +281,7 @@ private:
bool m_inAppMode = false; bool m_inAppMode = false;
bool m_keepRunningInAppMode = false; bool m_keepRunningInAppMode = false;
bool m_appModeResult = true; bool m_appModeResult = true;
bool m_aircraftGridMode;
}; };
#endif // LAUNCHERCONTROLLER_HXX #endif // LAUNCHERCONTROLLER_HXX

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24" version="1.1" fill="#1b7ad3" width="24px" height="24px">
<g id="surface1" fill="#1b7ad3">
<path style=" " d="M 4 4 L 4 8 L 8 8 L 8 4 Z M 10 4 L 10 8 L 14 8 L 14 4 Z M 16 4 L 16 8 L 20 8 L 20 4 Z M 4 10 L 4 14 L 8 14 L 8 10 Z M 10 10 L 10 14 L 14 14 L 14 10 Z M 16 10 L 16 14 L 20 14 L 20 10 Z M 4 16 L 4 20 L 8 20 L 8 16 Z M 10 16 L 10 20 L 14 20 L 14 16 Z M 16 16 L 16 20 L 20 20 L 20 16 Z " fill="#1b7ad3"/>
</g>
</svg>

After

(image error) Size: 564 B

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 26 26" version="1.1" fill="#1b7ad3" width="26px" height="26px">
<g id="surface1" fill="#1b7ad3">
<path style=" " d="M 0 4 L 0 6 L 26 6 L 26 4 Z M 0 12 L 0 14 L 26 14 L 26 12 Z M 0 20 L 0 22 L 26 22 L 26 20 Z " fill="#1b7ad3"/>
</g>
</svg>

After

(image error) Size: 374 B

View file

@ -0,0 +1,96 @@
import QtQuick 2.4
import FlightGear.Launcher 1.0
import "."
Item {
id: root
signal select(var uri);
signal showDetails(var uri)
readonly property bool __isSelected: (_launcher.selectedAircraft === model.uri)
Rectangle {
anchors.centerIn: parent
width: parent.width - 4
height: parent.height - 4
color: "transparent"
border.width: 1
border.color: "#dfdfdf"
}
MouseArea {
id: mouse
anchors.fill: parent
onClicked: {
if (__isSelected) {
root.showDetails(model.uri)
} else {
root.select(model.uri)
}
}
}
Column {
id: contentBox
width: parent.width
y: Style.margin
spacing: 2 //
Item {
id: thumbnailBox
width: 172
height: 128
anchors.horizontalCenter: parent.horizontalCenter
Rectangle {
anchors.centerIn: parent
border.width: 1
border.color: "#7f7f7f"
width: thumbnail.width
height: thumbnail.height
ThumbnailImage {
id: thumbnail
aircraftUri: model.uri
maximumSize.width: 172
maximumSize.height: 128
}
}
Button {
visible: hover.containsMouse && (model.packageStatus === LocalAircraftCache.PackageNotInstalled)
text: qsTr("Install")
onClicked: {
// drill down and also start the install
_launcher.requestInstallUpdate(model.uri)
root.showDetails(model.uri)
}
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
}
}
}
AircraftVariantChoice {
id: titleBox
width: parent.width
popupFontPixelSize: Style.baseFontPixelSize
aircraft: model.uri;
currentIndex: model.activeVariant
onSelected: {
model.activeVariant = index
root.select(model.uri)
}
}
}
MouseArea {
id: hover
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.NoButton
}
} // of root item

View file

@ -0,0 +1,77 @@
import QtQuick 2.0
import FlightGear.Launcher 1.0 as FG
Item {
id: root
property alias model: view.model
property alias header: view.header
signal showDetails(var uri);
function updateSelectionFromLauncher()
{
var row = model.indexForURI(_launcher.selectedAircraft);
if (row >= 0) {
view.currentIndex = row;
} else {
// clear selection in view, so we don't show something
// erroneous such as the previous value
view.currentIndex = -1;
}
}
onModelChanged: updateSelectionFromLauncher();
Component {
id: highlight
Rectangle {
gradient: Gradient {
GradientStop { position: 0.0; color: "#98A3B4" }
GradientStop { position: 1.0; color: "#5A6B83" }
}
}
}
GridView {
id: view
cellWidth: width / colCount
cellHeight: 128 + Style.strutSize
highlightMoveDuration: 0
readonly property int baseCellWidth: 172 + (Style.strutSize * 2)
readonly property int colCount: Math.floor(width / baseCellWidth)
anchors {
left: parent.left
top: parent.top
bottom: parent.bottom
right: scrollbar.left
topMargin: Style.margin
}
delegate: AircraftGridDelegate {
width: view.cellWidth
height: view.cellHeight
onSelect: {
view.currentIndex = model.index;
_launcher.selectedAircraft = uri;
}
onShowDetails: root.showDetails(uri)
}
clip: true
focus: true
highlight: highlight
}
Scrollbar {
id: scrollbar
anchors.right: parent.right
anchors.top: parent.top
height: view.height
flickable: view
}
}

View file

@ -6,8 +6,15 @@ FocusScope
{ {
id: root id: root
Component.onCompleted: { property var __model: null
aircraftList.updateSelectionFromLauncher(); property Component __header: null
property string __lastState: "installed"
function updateSelectionFromLauncher()
{
if (aircraftContent.item) {
aircraftContent.item.updateSelectionFromLauncher();
}
} }
Rectangle Rectangle
@ -16,6 +23,14 @@ FocusScope
height: searchButton.height + (Style.margin * 2) height: searchButton.height + (Style.margin * 2)
width: parent.width width: parent.width
GridToggleButton {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: Style.margin
gridMode: !_launcher.aircraftGridMode
onClicked: _launcher.aircraftGridMode = !_launcher.aircraftGridMode
}
Row { Row {
anchors.centerIn: parent anchors.centerIn: parent
spacing: Style.margin spacing: Style.margin
@ -25,7 +40,7 @@ FocusScope
text: qsTr("Installed Aircraft") text: qsTr("Installed Aircraft")
onClicked: { onClicked: {
root.state = "installed" root.state = "installed"
aircraftList.updateSelectionFromLauncher(); root.updateSelectionFromLauncher();
} }
active: root.state == "installed" active: root.state == "installed"
} }
@ -35,7 +50,7 @@ FocusScope
text: qsTr("Browse") text: qsTr("Browse")
onClicked: { onClicked: {
root.state = "browse" root.state = "browse"
aircraftList.updateSelectionFromLauncher(); root.updateSelectionFromLauncher();
} }
active: root.state == "browse" active: root.state == "browse"
} }
@ -46,7 +61,7 @@ FocusScope
text: qsTr("Updates") text: qsTr("Updates")
onClicked: { onClicked: {
root.state = "updates" root.state = "updates"
aircraftList.updateSelectionFromLauncher(); root.updateSelectionFromLauncher();
} }
active: root.state == "updates" active: root.state == "updates"
} }
@ -64,7 +79,7 @@ FocusScope
onSearch: { onSearch: {
_launcher.searchAircraftModel.setAircraftFilterString(term) _launcher.searchAircraftModel.setAircraftFilterString(term)
root.state = "search" root.state = "search"
aircraftList.updateSelectionFromLauncher(); root.updateSelectionFromLauncher();
} }
active: root.state == "search" active: root.state == "search"
@ -80,90 +95,65 @@ FocusScope
anchors.top: tabBar.bottom anchors.top: tabBar.bottom
} }
Component {
id: highlight
Rectangle {
gradient: Gradient {
GradientStop { position: 0.0; color: "#98A3B4" }
GradientStop { position: 1.0; color: "#5A6B83" }
}
}
}
Component { Component {
id: ratingsHeader id: ratingsHeader
AircraftRatingsPanel { AircraftRatingsPanel {
width: aircraftList.width - Style.strutSize * 2 width: aircraftContent.width
x: (aircraftList.width - width) / 2 onClearSelection: {
theList: aircraftList _launcher.selectedAircraft = "";
root.updateSelectionFromLauncher()
}
} }
} }
Component { Component {
id: noDefaultCatalogHeader id: noDefaultCatalogHeader
NoDefaultCatalogPanel { NoDefaultCatalogPanel {
width: aircraftList.width - Style.strutSize * 2 width: aircraftContent.width
x: (aircraftList.width - width) / 2
} }
} }
Component { Component {
id: updateAllHeader id: updateAllHeader
UpdateAllPanel { UpdateAllPanel {
width: aircraftList.width - Style.strutSize * 2 width: aircraftContent.width
x: (aircraftList.width - width) / 2
} }
} }
ListView { Component {
id: aircraftList id: emptyHeader
Item {
}
}
Loader {
id: aircraftContent
source: _launcher.aircraftGridMode ? "qrc:///qml/AircraftGridView.qml"
: "qrc:///qml/AircraftListView.qml"
anchors { anchors {
left: parent.left left: parent.left
top: tabBarDivider.bottom top: tabBarDivider.bottom
bottom: parent.bottom bottom: parent.bottom
right: scrollbar.left right: parent.right
topMargin: Style.margin topMargin: Style.margin
} }
delegate: AircraftCompactDelegate { Binding {
onSelect: { target: aircraftContent.item
aircraftList.currentIndex = model.index; property: "model"
_launcher.selectedAircraft = uri; value: root.__model
}
onShowDetails: root.showDetails(uri)
} }
clip: true Binding {
focus: true target: aircraftContent.item
property: "header"
value: root.__header
}
// prevent mouse wheel interactions when the details view is Connections {
// visible, since it has its own flickable target: aircraftContent.item
enabled: !detailsView.visible onShowDetails: root.showDetails(uri)
highlight: highlight
highlightMoveDuration: __realHighlightMoveDuration
// saved here becuase we need to reset highlightMoveDuration
// when doing a progrmatic set
readonly property int __realHighlightMoveDuration: 200
function updateSelectionFromLauncher()
{
model.selectVariantForAircraftURI(_launcher.selectedAircraft);
var row = model.indexForURI(_launcher.selectedAircraft);
if (row >= 0) {
// sequence here is necessary so progrommatic moves
// are instant
highlightMoveDuration = 0;
currentIndex = row;
highlightMoveDuration = __realHighlightMoveDuration;
} else {
// clear selection in view, so we don't show something
// erroneous such as the previous value
currentIndex = -1;
}
} }
} }
@ -173,7 +163,7 @@ FocusScope
left: parent.left left: parent.left
top: tabBar.bottom top: tabBar.bottom
bottom: parent.bottom bottom: parent.bottom
right: scrollbar.left right: parent.right
} }
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
@ -182,49 +172,42 @@ FocusScope
visible: (root.state == "updates") && (_launcher.aircraftWithUpdatesModel.count == 0) visible: (root.state == "updates") && (_launcher.aircraftWithUpdatesModel.count == 0)
} }
Scrollbar {
id: scrollbar
anchors.right: parent.right
anchors.top: tabBar.bottom
height: aircraftList.height
flickable: aircraftList
}
state: "installed" state: "installed"
states: [ states: [
State { State {
name: "installed" name: "installed"
PropertyChanges { PropertyChanges {
target: aircraftList target: root
model: _launcher.installedAircraftModel __model: _launcher.installedAircraftModel
__header: emptyHeader
} }
}, },
State { State {
name: "search" name: "search"
PropertyChanges { PropertyChanges {
target: aircraftList target: root
model: _launcher.searchAircraftModel __model: _launcher.searchAircraftModel
header: null __header: emptyHeader
} }
}, },
State { State {
name: "browse" name: "browse"
PropertyChanges { PropertyChanges {
target: aircraftList target: root
model: _launcher.browseAircraftModel __model: _launcher.browseAircraftModel
header: _addOns.showNoOfficialHangar ? noDefaultCatalogHeader : ratingsHeader __header: _addOns.showNoOfficialHangar ? noDefaultCatalogHeader : ratingsHeader
} }
}, },
State { State {
name: "updates" name: "updates"
PropertyChanges { PropertyChanges {
target: aircraftList target: root
model: _launcher.aircraftWithUpdatesModel __model: _launcher.aircraftWithUpdatesModel
header: (_launcher.aircraftWithUpdatesModel.count > 0) ? updateAllHeader : null __header: (_launcher.aircraftWithUpdatesModel.count > 0) ? updateAllHeader : emptyHeader
} }
} }
] ]
@ -239,6 +222,8 @@ FocusScope
function goBack() function goBack()
{ {
// details view can change the aircraft URI / variant
updateSelectionFromLauncher();
detailsView.visible = false; detailsView.visible = false;
} }
@ -250,15 +235,9 @@ FocusScope
Button { Button {
anchors { left: parent.left; top: parent.top; margins: Style.margin } anchors { left: parent.left; top: parent.top; margins: Style.margin }
width: Style.strutSize width: Style.strutSize
id: backButton id: backButton
text: "< Back" text: "< Back"
onClicked: { onClicked: root.goBack();
// ensure that if the variant was changed inside the detailsView,
// that we update our selection correctly
aircraftList.updateSelectionFromLauncher();
root.goBack();
}
} }
} }
} }

View file

@ -0,0 +1,80 @@
import QtQuick 2.0
import FlightGear.Launcher 1.0 as FG
import "."
Item {
id: root
property alias model: aircraftList.model
property alias header: aircraftList.header
signal showDetails(var uri);
function updateSelectionFromLauncher()
{
model.selectVariantForAircraftURI(_launcher.selectedAircraft);
var row = model.indexForURI(_launcher.selectedAircraft);
if (row >= 0) {
// sequence here is necessary so progrommatic moves
// are instant
aircraftList.highlightMoveDuration = 0;
aircraftList.currentIndex = row;
aircraftList.highlightMoveDuration = aircraftList.__realHighlightMoveDuration;
} else {
// clear selection in view, so we don't show something
// erroneous such as the previous value
aircraftList.currentIndex = -1;
}
}
onModelChanged: updateSelectionFromLauncher()
Component {
id: highlight
Rectangle {
gradient: Gradient {
GradientStop { position: 0.0; color: "#98A3B4" }
GradientStop { position: 1.0; color: "#5A6B83" }
}
}
}
ListView {
id: aircraftList
anchors {
left: parent.left
top: parent.top
bottom: parent.bottom
right: scrollbar.left
topMargin: Style.margin
}
delegate: AircraftCompactDelegate {
onSelect: {
aircraftList.currentIndex = model.index;
_launcher.selectedAircraft = uri;
}
onShowDetails: root.showDetails(uri)
}
clip: true
focus: true
highlight: highlight
highlightMoveDuration: __realHighlightMoveDuration
// saved here becuase we need to reset highlightMoveDuration
// when doing a progrmatic set
readonly property int __realHighlightMoveDuration: 200
}
Scrollbar {
id: scrollbar
anchors.right: parent.right
anchors.top: parent.top
height: aircraftList.height
flickable: aircraftList
}
}

View file

@ -4,7 +4,8 @@ import "."
ListHeaderBox ListHeaderBox
{ {
property ListView theList: null id: root
signal clearSelection();
contents: [ contents: [
@ -39,7 +40,7 @@ ListHeaderBox
onClicked: { onClicked: {
// clear selection so we don't jump to the selected item // clear selection so we don't jump to the selected item
// each time the proxy model changes. // each time the proxy model changes.
theList.currentIndex = -1; root.clearSelection();
editRatingsPanel.visible = true editRatingsPanel.visible = true
} }

View file

@ -10,11 +10,13 @@ Rectangle {
implicitHeight: title.implicitHeight implicitHeight: title.implicitHeight
radius: 4 radius: Style.roundRadius
border.color: Style.frameColor border.color: Style.frameColor
border.width: headingMouseArea.containsMouse ? 1 : 0 border.width: headingMouseArea.containsMouse ? 1 : 0
color: headingMouseArea.containsMouse ? "#7fffffff" : "transparent" color: headingMouseArea.containsMouse ? "#7fffffff" : "transparent"
readonly property int centerX: width / 2
readonly property bool __enabled: aircraftInfo.numVariants > 1 readonly property bool __enabled: aircraftInfo.numVariants > 1
property alias aircraft: aircraftInfo.uri property alias aircraft: aircraftInfo.uri
@ -28,33 +30,53 @@ Rectangle {
signal selected(var index) signal selected(var index)
Text {
id: title
anchors.verticalCenter: parent.verticalCenter
anchors.right: upDownIcon.left
anchors.left: parent.left
anchors.leftMargin: 4
anchors.rightMargin: 4
horizontalAlignment: Text.AlignHCenter
font.pixelSize: Style.baseFontPixelSize * 2
text: aircraftInfo.name
fontSizeMode: Text.Fit
elide: Text.ElideRight
maximumLineCount: 1
color: headingMouseArea.containsMouse ? Style.themeColor : Style.baseTextColor
}
Image {
id: upDownIcon // Image {
source: "qrc:///up-down-arrow" // id: upDownIcon
anchors.right: parent.right // source: "qrc:///up-down-arrow"
anchors.rightMargin: 8 // x: root.centerX + Math.min(title.implicitWidth * 0.5, title.width * 0.5)
anchors.verticalCenter: parent.verticalCenter // anchors.verticalCenter: parent.verticalCenter
visible: __enabled // visible: __enabled
// }
Row {
anchors.centerIn: parent
height: title.implicitHeight
width: childrenRect.width
Text {
id: title
anchors.verticalCenter: parent.verticalCenter
// this ugly logic is to keep the up-down arrow at the right
// hand side of the text, but allow the font scaling to work if
// we're short on horizontal space
width: Math.min(implicitWidth,
root.width - (Style.margin * 2) - (__enabled ? upDownIcon.implicitWidth : 0))
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: Style.baseFontPixelSize * 2
text: aircraftInfo.name
fontSizeMode: Text.Fit
elide: Text.ElideRight
maximumLineCount: 1
color: headingMouseArea.containsMouse ? Style.themeColor : Style.baseTextColor
}
Image {
id: upDownIcon
source: "qrc:///up-down-arrow"
// x: root.centerX + Math.min(title.implicitWidth * 0.5, title.width * 0.5)
anchors.verticalCenter: parent.verticalCenter
visible: __enabled
width: __enabled ? implicitWidth : 0
}
} }
MouseArea { MouseArea {

View file

@ -0,0 +1,43 @@
import QtQuick 2.0
import "."
Rectangle {
id: root
radius: Style.roundRadius
border.width: 1
border.color: Style.themeColor
width: height
height: Style.baseFontPixelSize + Style.margin * 2
color: mouse.containsMouse ? Style.minorFrameColor : "white"
property bool gridMode: false
signal clicked();
Image {
id: icon
width: parent.width - Style.margin
height: parent.height - Style.margin
anchors.centerIn: parent
source: root.gridMode ? "qrc:///svg/icon-grid-view"
: "qrc:///svg/icon-list-view"
}
MouseArea {
id: mouse
hoverEnabled: true
onClicked: root.clicked();
anchors.fill: parent
}
Text {
anchors.left: root.right
anchors.leftMargin: Style.margin
anchors.verticalCenter: root.verticalCenter
visible: mouse.containsMouse
color: Style.baseTextColor
font.pixelSize: Style.baseFontPixelSize
text: root.gridMode ? qsTr("Switch to grid view")
: qsTr("Switch to list view")
}
}

View file

@ -11,7 +11,8 @@ Item {
Rectangle { Rectangle {
id: contentBox id: contentBox
width: parent.width width: parent.width - Style.strutSize * 2
x: Style.strutSize
height: Style.strutSize height: Style.strutSize
y: Style.margin y: Style.margin
color: "white" color: "white"

View file

@ -123,6 +123,10 @@
<file>qml/RouteLegsView.qml</file> <file>qml/RouteLegsView.qml</file>
<file>qml/OverlayMenu.qml</file> <file>qml/OverlayMenu.qml</file>
<file>qml/PopupChoiceItem.qml</file> <file>qml/PopupChoiceItem.qml</file>
<file>qml/AircraftGridDelegate.qml</file>
<file>qml/AircraftGridView.qml</file>
<file>qml/AircraftListView.qml</file>
<file>qml/GridToggleButton.qml</file>
</qresource> </qresource>
<qresource prefix="/preview"> <qresource prefix="/preview">
<file alias="close-icon">preview-close.png</file> <file alias="close-icon">preview-close.png</file>
@ -139,5 +143,7 @@
<file alias="toolbox-aircraft">assets/icons8-aircraft.svg</file> <file alias="toolbox-aircraft">assets/icons8-aircraft.svg</file>
<file alias="toolbox-fly-alt">assets/icons8-rocket.svg</file> <file alias="toolbox-fly-alt">assets/icons8-rocket.svg</file>
<file alias="toolbox-fly-heli">assets/icons8-helicopter.svg</file> <file alias="toolbox-fly-heli">assets/icons8-helicopter.svg</file>
<file alias="icon-grid-view">assets/icons8-grid-view.svg</file>
<file alias="icon-list-view">assets/icons8-menu.svg</file>
</qresource> </qresource>
</RCC> </RCC>