From 7ea138038e8189f0c2f59f3561ff32e2b2668e46 Mon Sep 17 00:00:00 2001
From: Automatic Release Builder <build@flightgear.org>
Date: Mon, 28 Sep 2020 16:18:32 +0100
Subject: [PATCH] First-run page for the launcher.

Appears on first launch, gives us a chance to point out some policy
things and where to get help.
---
 src/GUI/LauncherController.cxx |  14 ++++
 src/GUI/LauncherController.hxx |  17 ++++
 src/GUI/qml/Button.qml         |  13 ++-
 src/GUI/qml/FirstRun.qml       | 140 +++++++++++++++++++++++++++++++++
 src/GUI/qml/Launcher.qml       |  12 +++
 src/GUI/qml/Style.qml          |   1 +
 src/GUI/resources.qrc          |   3 +-
 7 files changed, 196 insertions(+), 4 deletions(-)
 create mode 100644 src/GUI/qml/FirstRun.qml

diff --git a/src/GUI/LauncherController.cxx b/src/GUI/LauncherController.cxx
index 3ba248533..6354334b5 100644
--- a/src/GUI/LauncherController.cxx
+++ b/src/GUI/LauncherController.cxx
@@ -133,6 +133,20 @@ LauncherController::LauncherController(QObject *parent, QWindow* window) :
         const auto ws = static_cast<Qt::WindowState>(settings.value("window-state").toInt());
         m_window->setWindowState(ws);
     }
+
+    // count launches; we use this to trigger first-run and periodic notices
+    // in the UI.
+    m_launchCount = settings.value("launch-count", 0).toInt();
+    settings.setValue("launch-count", m_launchCount + 1);
+
+    std::ostringstream os;
+    string_list versionParts = simgear::strutils::split(FLIGHTGEAR_VERSION, ".");
+    if (versionParts.size() >= 2) {
+        // build a setting key like launch-count-2020-2
+        QString versionedCountKey = QString::fromStdString("launch-count-" + versionParts.at(0) + "-" + versionParts.at(1));
+        m_versionLaunchCount = settings.value(versionedCountKey, 0).toInt();
+        settings.setValue(versionedCountKey, m_versionLaunchCount + 1);
+    }
 }
 
 void LauncherController::initQML()
diff --git a/src/GUI/LauncherController.hxx b/src/GUI/LauncherController.hxx
index 449a18cd1..915ccc1e9 100644
--- a/src/GUI/LauncherController.hxx
+++ b/src/GUI/LauncherController.hxx
@@ -91,6 +91,10 @@ class LauncherController : public QObject
     Q_PROPERTY(bool inAppMode READ inApp NOTIFY inAppChanged)
 
     Q_PROPERTY(bool aircraftGridMode READ aircraftGridMode WRITE setAircraftGridMode NOTIFY aircraftGridModeChanged)
+
+    Q_PROPERTY(int launchCount READ launchCount CONSTANT);
+    Q_PROPERTY(int versionLaunchCount READ versionLaunchCount CONSTANT);
+
 public:
     explicit LauncherController(QObject *parent, QWindow* win);
 
@@ -202,6 +206,17 @@ public:
     {
         return m_inAppMode;
     }
+
+    int launchCount() const
+    {
+        return m_launchCount;
+    }
+
+    int versionLaunchCount() const
+    {
+        return m_versionLaunchCount;
+    }
+
 signals:
 
     void selectedAircraftChanged(QUrl selectedAircraft);
@@ -294,6 +309,8 @@ private:
 	bool m_keepRunningInAppMode = false;
     bool m_appModeResult = true;
     bool m_aircraftGridMode;
+    int m_launchCount = 0;
+    int m_versionLaunchCount = 0;
 };
 
 #endif // LAUNCHERCONTROLLER_HXX
diff --git a/src/GUI/qml/Button.qml b/src/GUI/qml/Button.qml
index 4731ae115..a447a5ff2 100644
--- a/src/GUI/qml/Button.qml
+++ b/src/GUI/qml/Button.qml
@@ -9,19 +9,26 @@ Rectangle {
     property bool enabled: true
     property bool destructiveAction: false
 
-    readonly property string __baseColor: destructiveAction ? Style.destructiveActionColor : Style.themeColor
+    readonly property string __baseColor: destructiveAction ? Style.destructiveActionColor :
+                                                              (invertColor ? "white" : Style.themeColor)
+
+    readonly property string __activeColor: invertColor ? Style.inverseActiveColor : Style.activeColor
+    readonly property string __textColor: invertColor ? Style.frameColor : "white"
+
     signal clicked
 
+    property bool invertColor: false
+
     width: Math.max(Style.strutSize * 2, buttonText.implicitWidth + radius * 2)
     height: buttonText.implicitHeight + (radius * 2)
     radius: Style.roundRadius
 
-    color: enabled ? (mouse.containsMouse ? Style.activeColor : __baseColor) : Style.disabledThemeColor
+    color: enabled ? (mouse.containsMouse ? __activeColor : __baseColor) : Style.disabledThemeColor
 
     Text {
         id: buttonText
         anchors.centerIn: parent
-        color: "white"
+        color: root.__textColor
         text: (mouse.containsMouse && hoverText != "") ? root.hoverText : root.text
         font.pixelSize: Style.baseFontPixelSize
     }
diff --git a/src/GUI/qml/FirstRun.qml b/src/GUI/qml/FirstRun.qml
new file mode 100644
index 000000000..01314c2cc
--- /dev/null
+++ b/src/GUI/qml/FirstRun.qml
@@ -0,0 +1,140 @@
+import QtQuick 2.4
+import FlightGear 1.0
+import FlightGear.Launcher 1.0
+import "."
+
+Rectangle {
+    color: Style.themeColor
+    id: root
+
+    Item  {
+        id: imageClipFrame
+        clip: true
+
+        height: root.height * 0.5
+        anchors {
+            left: parent.left
+            right: parent.right
+            top: parent.top
+        }
+
+        PreviewImage {
+            id: preview
+
+            anchors.centerIn: parent
+
+            // over-zoom the preview to fill the entire space available
+            readonly property double scale: Math.max(root.width / sourceSize.width,
+                                                             imageClipFrame.height / sourceSize.height)
+
+            width: height * aspectRatio
+            height: scale * sourceSize.height
+
+            property var urlsList: _launcher.defaultSplashUrls()
+            imageUrl: urlsList[0]
+        }
+
+        Text {
+            id: logoText
+            width: parent.width - Style.strutSize
+
+            anchors {
+                top: parent.top
+                topMargin: Style.strutSize
+            }
+
+            font.pointSize: Style.strutSize * 3
+            font.italic: true
+            font.bold: true
+
+            horizontalAlignment: Text.AlignHCenter
+            fontSizeMode: Text.Fit
+            text: "FlightGear " + _launcher.versionString
+            color: "white"
+            style: Text.Outline
+            styleColor: "black"
+        }
+    }
+
+
+
+    Column {
+        anchors {
+            left: parent.left
+            right: parent.right
+            top: imageClipFrame.bottom
+
+            margins: Style.strutSize
+        }
+
+        spacing: Style.strutSize
+
+        Text {
+            width: parent.width
+            font.pixelSize: Style.baseFontPixelSize * 1.5
+            color: "white"
+            wrapMode: Text.WordWrap
+
+            readonly property string forumLink: "href=\"http://forum.flightgear.org\"";
+
+            text: qsTr("Welcome to FlightGear, the open-source flight simulator. " +
+                         "Everything in this software is the work of volunteers; we hope " +
+                         "you enjoy it. If you find problems, or would like to contribute, " +
+                         "please <a %1>visit our user forum</a>.").arg(forumLink)
+
+            onLinkActivated: {
+                Qt.openUrlExternally(link)
+            }
+        }
+
+        Text {
+            width: parent.width
+            font.pixelSize: Style.baseFontPixelSize * 1.5
+            color: "white"
+            wrapMode: Text.WordWrap
+
+            readonly property string gplLink: "href=\"https://www.gnu.org/licenses/gpl-3.0.html\"";
+
+            text: qsTr("FlightGear is Free software, licensed under the <a %1>GNU General Public License</a>. " +
+                         "This means you are are free to use the software, customise it, or make fixes to it, so long as " +
+                         "you share your changes with the community.").arg(gplLink)
+
+            onLinkActivated: {
+                Qt.openUrlExternally(link)
+            }
+        }
+
+        Text {
+            width: parent.width
+            font.pixelSize: Style.baseFontPixelSize * 1.5
+            color: "white"
+
+            wrapMode: Text.WordWrap
+
+            text: qsTr("FlightGear can automatically report crashes and errors to the development team, " +
+                       "which helps to improve the software for everyone. This reporting is anonymous but " +
+                       "contains information such as the aircraft in use, your operating system and graphics driver. " +
+                       "You can enable or disable this reporting in the 'Settings' page."
+                       )
+        }
+
+        Item {
+            width: parent.width
+            height: childrenRect.height
+
+            Button {
+                invertColor: true
+                text: qsTrId("Okay");
+                anchors.right: parent.right
+
+                onClicked: {
+                    OverlayShared.globalOverlay.dismissOverlay();
+                }
+            }
+        }
+    } // of column
+
+
+
+
+}
diff --git a/src/GUI/qml/Launcher.qml b/src/GUI/qml/Launcher.qml
index fee70c143..ce51b4078 100644
--- a/src/GUI/qml/Launcher.qml
+++ b/src/GUI/qml/Launcher.qml
@@ -43,6 +43,18 @@ Item {
     Component.onCompleted:
     {
        _launcher.minimumWindowSize = Qt.size(Style.strutSize * 12, sidebar.minimumHeight);
+
+        if (_launcher.versionLaunchCount == 0) {
+            popupOverlay.showOverlay(firstRun)
+        }
+    }
+
+    Component {
+        id: firstRun
+        FirstRun {
+            width: root.width
+            height: root.height
+        }
     }
 
     Connections {
diff --git a/src/GUI/qml/Style.qml b/src/GUI/qml/Style.qml
index b2880c418..8e0ae5018 100644
--- a/src/GUI/qml/Style.qml
+++ b/src/GUI/qml/Style.qml
@@ -16,6 +16,7 @@ QtObject
     readonly property string destructiveActionColor: "#c62703"
 
     readonly property string activeColor: Qt.darker(themeColor)
+    readonly property string inverseActiveColor: "#2f2f2f"
 
     readonly property string inactiveThemeColor: "#9f9f9f"
     readonly property string disabledThemeColor: disabledTextColor
diff --git a/src/GUI/resources.qrc b/src/GUI/resources.qrc
index d1846bcec..d05560ad4 100644
--- a/src/GUI/resources.qrc
+++ b/src/GUI/resources.qrc
@@ -130,9 +130,10 @@
         <file>qml/EnableDisableButton.qml</file>
         <file>qml/IconButton.qml</file>
         <file>qml/FavouriteToggleButton.qml</file>
-         <file>qml/VariantMenu.qml</file>
+        <file>qml/VariantMenu.qml</file>
         <file alias="favourite-icon-filled">assets/icons8-christmas-star-filled.png</file>
         <file alias="favourite-icon-outline">assets/icons8-christmas-star-outline.png</file>
+        <file>qml/FirstRun.qml</file>
     </qresource>
     <qresource prefix="/preview">
         <file alias="close-icon">assets/preview-close.png</file>