mirror of
https://github.com/cmclark00/retro-imager.git
synced 2025-05-18 07:55:21 +01:00
Shift+Ctrl+X option screen: allow persisting settings
This commit is contained in:
parent
a6150f7bc5
commit
abbed47f97
6 changed files with 355 additions and 34 deletions
142
OptionsPopup.qml
142
OptionsPopup.qml
|
@ -19,6 +19,7 @@ Popup {
|
|||
padding: 0
|
||||
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
||||
property bool initialized: false
|
||||
property bool hasSavedSettings: false
|
||||
property string config
|
||||
property string cmdline
|
||||
property string firstrun
|
||||
|
@ -87,8 +88,21 @@ Popup {
|
|||
ColumnLayout {
|
||||
|
||||
GroupBox {
|
||||
title: qsTr("Image customization options (for this session only)")
|
||||
Layout.fillWidth: true
|
||||
title: qsTr("Image customization options")
|
||||
label: RowLayout {
|
||||
Label {
|
||||
text: parent.parent.title
|
||||
}
|
||||
ComboBox {
|
||||
id: comboSaveSettings
|
||||
model: {
|
||||
[qsTr("for this session only"),
|
||||
qsTr("to always use")]
|
||||
}
|
||||
Layout.minimumWidth: 250
|
||||
Layout.maximumHeight: 40
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: -10
|
||||
|
@ -97,26 +111,24 @@ Popup {
|
|||
id: chkOverscan
|
||||
text: qsTr("Disable overscan")
|
||||
}
|
||||
RowLayout {
|
||||
CheckBox {
|
||||
id: chkHostname
|
||||
text: qsTr("Set hostname")
|
||||
text: qsTr("Set hostname:")
|
||||
onCheckedChanged: {
|
||||
if (checked) {
|
||||
fieldHostname.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
enabled: chkHostname.checked
|
||||
Layout.leftMargin: 40
|
||||
|
||||
TextField {
|
||||
id: fieldHostname
|
||||
enabled: chkHostname.checked
|
||||
text: "raspberrypi"
|
||||
}
|
||||
Text {
|
||||
text : ".local"
|
||||
color: parent.enabled ? "black" : "grey"
|
||||
color: chkHostname.checked ? "black" : "grey"
|
||||
}
|
||||
}
|
||||
CheckBox {
|
||||
|
@ -163,6 +175,16 @@ Popup {
|
|||
id: fieldUserPassword
|
||||
echoMode: TextInput.Password
|
||||
Layout.minimumWidth: 200
|
||||
property bool alreadyCrypted: false
|
||||
|
||||
onTextEdited: {
|
||||
if (alreadyCrypted) {
|
||||
/* User is trying to edit saved
|
||||
(crypted) password, clear field */
|
||||
alreadyCrypted = false
|
||||
clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -326,6 +348,7 @@ Popup {
|
|||
}
|
||||
|
||||
applySettings()
|
||||
saveSettings()
|
||||
popup.close()
|
||||
}
|
||||
Material.foreground: "#ffffff"
|
||||
|
@ -338,14 +361,47 @@ Popup {
|
|||
}
|
||||
}
|
||||
|
||||
function openPopup() {
|
||||
if (!initialized) {
|
||||
function initialize() {
|
||||
chkBeep.checked = imageWriter.getBoolSetting("beep")
|
||||
chkTelemtry.checked = imageWriter.getBoolSetting("telemetry")
|
||||
chkEject.checked = imageWriter.getBoolSetting("eject")
|
||||
var settings = imageWriter.getSavedCustomizationSettings()
|
||||
fieldTimezone.model = imageWriter.getTimezoneList()
|
||||
fieldPublicKey.text = imageWriter.getDefaultPubKey()
|
||||
fieldWifiCountry.model = imageWriter.getCountryList()
|
||||
|
||||
if (Object.keys(settings).length) {
|
||||
comboSaveSettings.currentIndex = 1
|
||||
hasSavedSettings = true
|
||||
}
|
||||
if ('disableOverscan' in settings) {
|
||||
chkOverscan.checked = true
|
||||
}
|
||||
if ('hostname' in settings) {
|
||||
fieldHostname.text = settings.hostname
|
||||
chkHostname.checked = true
|
||||
}
|
||||
if ('sshUserPassword' in settings) {
|
||||
fieldUserPassword.text = settings.sshUserPassword
|
||||
fieldUserPassword.alreadyCrypted = true
|
||||
chkSSH.checked = true
|
||||
radioPasswordAuthentication.checked = true
|
||||
}
|
||||
if ('sshAuthorizedKeys' in settings) {
|
||||
fieldPublicKey.text = settings.sshAuthorizedKeys
|
||||
chkSSH.checked = true
|
||||
radioPubKeyAuthentication.checked = true
|
||||
}
|
||||
if ('wifiSSID' in settings) {
|
||||
fieldWifiSSID.text = settings.wifiSSID
|
||||
chkShowPassword.checked = false
|
||||
fieldWifiPassword.text = settings.wifiPassword
|
||||
fieldWifiCountry.currentIndex = fieldWifiCountry.find(settings.wifiCountry)
|
||||
if (fieldWifiCountry.currentIndex == -1) {
|
||||
fieldWifiCountry.editText = settings.wifiCountry
|
||||
}
|
||||
chkWifi.checked = true
|
||||
} else {
|
||||
fieldWifiCountry.currentIndex = fieldWifiCountry.find("GB")
|
||||
fieldWifiSSID.text = imageWriter.getSSID()
|
||||
if (fieldWifiSSID.text.length) {
|
||||
|
@ -354,23 +410,43 @@ Popup {
|
|||
chkShowPassword.checked = false
|
||||
}
|
||||
}
|
||||
var tz = imageWriter.getTimezone()
|
||||
}
|
||||
|
||||
var tz;
|
||||
if ('timezone' in settings) {
|
||||
chkLocale.checked = true
|
||||
tz = settings.timezone
|
||||
} else {
|
||||
tz = imageWriter.getTimezone()
|
||||
}
|
||||
var tzidx = fieldTimezone.find(tz)
|
||||
if (tzidx === -1) {
|
||||
fieldTimezone.editText = tz
|
||||
} else {
|
||||
fieldTimezone.currentIndex = tzidx
|
||||
}
|
||||
if ('keyboardLayout' in settings) {
|
||||
fieldKeyboardLayout.text = settings.keyboardLayout
|
||||
} else {
|
||||
/* Lacking an easy cross-platform to fetch keyboard layout
|
||||
from host system, just default to "gb" for people in
|
||||
UK time zone for now, and "us" for everyone else */
|
||||
if (tz == "Europe/London") {
|
||||
fieldKeyboardLayout.text = "gb"
|
||||
}
|
||||
}
|
||||
if ('skipFirstUse' in settings) {
|
||||
chkSkipFirstUse.checked = true
|
||||
}
|
||||
|
||||
initialized = true
|
||||
}
|
||||
|
||||
function openPopup() {
|
||||
if (!initialized) {
|
||||
initialize()
|
||||
}
|
||||
|
||||
open()
|
||||
}
|
||||
|
||||
|
@ -407,7 +483,8 @@ Popup {
|
|||
addFirstRun("FIRSTUSERHOME=`getent passwd 1000 | cut -d: -f6`")
|
||||
|
||||
if (radioPasswordAuthentication.checked) {
|
||||
addFirstRun("echo \"$FIRSTUSER:\""+escapeshellarg(imageWriter.crypt(fieldUserPassword.text))+" | chpasswd -e")
|
||||
var cryptedPassword = fieldUserPassword.alreadyCrypted ? fieldUserPassword.text : imageWriter.crypt(fieldUserPassword.text)
|
||||
addFirstRun("echo \"$FIRSTUSER:\""+escapeshellarg(cryptedPassword)+" | chpasswd -e")
|
||||
}
|
||||
if (radioPubKeyAuthentication.checked) {
|
||||
var pubkey = fieldPublicKey.text.replace(/\n/g, "")
|
||||
|
@ -466,6 +543,47 @@ Popup {
|
|||
}
|
||||
|
||||
imageWriter.setImageCustomization(config, cmdline, firstrun)
|
||||
}
|
||||
|
||||
function saveSettings()
|
||||
{
|
||||
if (comboSaveSettings.currentIndex == 1) {
|
||||
hasSavedSettings = true
|
||||
var settings = { };
|
||||
if (chkOverscan.checked) {
|
||||
settings.disableOverscan = true
|
||||
}
|
||||
if (chkHostname.checked && fieldHostname.length) {
|
||||
settings.hostname = fieldHostname.text
|
||||
}
|
||||
if (chkSSH.checked) {
|
||||
if (radioPasswordAuthentication.checked) {
|
||||
settings.sshUserPassword = fieldUserPassword.alreadyCrypted ? fieldUserPassword.text : imageWriter.crypt(fieldUserPassword.text)
|
||||
}
|
||||
if (radioPubKeyAuthentication.checked) {
|
||||
settings.sshAuthorizedKeys = fieldPublicKey.text
|
||||
}
|
||||
}
|
||||
if (chkWifi.checked) {
|
||||
settings.wifiSSID = fieldWifiSSID.text
|
||||
settings.wifiPassword = fieldWifiPassword.text
|
||||
settings.wifiCountry = fieldWifiCountry.editText
|
||||
}
|
||||
if (chkLocale.checked) {
|
||||
settings.timezone = fieldTimezone.editText
|
||||
settings.keyboardLayout = fieldKeyboardLayout.text
|
||||
if (chkSkipFirstUse.checked) {
|
||||
settings.skipFirstUse = true
|
||||
}
|
||||
}
|
||||
|
||||
imageWriter.setSavedCustomizationSettings(settings)
|
||||
|
||||
} else if (hasSavedSettings) {
|
||||
imageWriter.clearSavedCustomizationSettings()
|
||||
hasSavedSettings = false
|
||||
}
|
||||
|
||||
imageWriter.setSetting("beep", chkBeep.checked)
|
||||
imageWriter.setSetting("eject", chkEject.checked)
|
||||
imageWriter.setSetting("telemetry", chkTelemtry.checked)
|
||||
|
|
138
UseSavedSettingsPopup.qml
Normal file
138
UseSavedSettingsPopup.qml
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright (C) 2021 Raspberry Pi (Trading) Limited
|
||||
*/
|
||||
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Controls.Material 2.2
|
||||
|
||||
Popup {
|
||||
id: msgpopup
|
||||
x: 75
|
||||
y: (parent.height-height)/2
|
||||
width: parent.width-150
|
||||
height: msgpopupbody.implicitHeight+150
|
||||
padding: 0
|
||||
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
||||
|
||||
signal yes()
|
||||
signal no()
|
||||
signal editSettings()
|
||||
|
||||
// background of title
|
||||
Rectangle {
|
||||
color: "#f5f5f5"
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
height: 35
|
||||
width: parent.width
|
||||
}
|
||||
// line under title
|
||||
Rectangle {
|
||||
color: "#afafaf"
|
||||
width: parent.width
|
||||
y: 35
|
||||
implicitHeight: 1
|
||||
}
|
||||
|
||||
Text {
|
||||
id: msgx
|
||||
text: "X"
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.rightMargin: 25
|
||||
anchors.topMargin: 10
|
||||
font.family: roboto.name
|
||||
font.bold: true
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
msgpopup.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 20
|
||||
anchors.fill: parent
|
||||
|
||||
Text {
|
||||
id: msgpopupheader
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 10
|
||||
font.family: roboto.name
|
||||
font.bold: true
|
||||
text: qsTr("Warning: advanced settings set")
|
||||
}
|
||||
|
||||
Text {
|
||||
id: msgpopupbody
|
||||
font.pointSize: 12
|
||||
wrapMode: Text.Wrap
|
||||
textFormat: Text.StyledText
|
||||
font.family: roboto.name
|
||||
Layout.maximumWidth: msgpopup.width-50
|
||||
Layout.fillHeight: true
|
||||
Layout.leftMargin: 25
|
||||
Layout.topMargin: 25
|
||||
Accessible.name: text.replace(/<\/?[^>]+(>|$)/g, "")
|
||||
text: qsTr("Would you like to apply the image customization settings saved earlier?")
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignCenter | Qt.AlignBottom
|
||||
Layout.bottomMargin: 10
|
||||
spacing: 20
|
||||
|
||||
Button {
|
||||
text: qsTr("NO, CLEAR SETTINGS")
|
||||
onClicked: {
|
||||
msgpopup.close()
|
||||
msgpopup.no()
|
||||
}
|
||||
Material.foreground: "#ffffff"
|
||||
Material.background: "#c51a4a"
|
||||
font.family: roboto.name
|
||||
Accessible.onPressAction: clicked()
|
||||
}
|
||||
|
||||
Button {
|
||||
text: qsTr("YES")
|
||||
onClicked: {
|
||||
msgpopup.close()
|
||||
msgpopup.yes()
|
||||
}
|
||||
Material.foreground: "#ffffff"
|
||||
Material.background: "#c51a4a"
|
||||
font.family: roboto.name
|
||||
Accessible.onPressAction: clicked()
|
||||
}
|
||||
|
||||
Button {
|
||||
text: qsTr("EDIT SETTINGS")
|
||||
onClicked: {
|
||||
msgpopup.close()
|
||||
msgpopup.editSettings()
|
||||
}
|
||||
Material.foreground: "#ffffff"
|
||||
Material.background: "#c51a4a"
|
||||
font.family: roboto.name
|
||||
Accessible.onPressAction: clicked()
|
||||
}
|
||||
|
||||
Text { text: " " }
|
||||
}
|
||||
}
|
||||
|
||||
function openPopup() {
|
||||
open()
|
||||
// trigger screen reader to speak out message
|
||||
msgpopupbody.forceActiveFocus()
|
||||
}
|
||||
}
|
|
@ -926,6 +926,45 @@ QString ImageWriter::crypt(const QByteArray &password)
|
|||
return sha256_crypt(password.constData(), salt.constData());
|
||||
}
|
||||
|
||||
void ImageWriter::setSavedCustomizationSettings(const QVariantMap &map)
|
||||
{
|
||||
_settings.beginGroup("imagecustomization");
|
||||
_settings.remove("");
|
||||
for (QString key : map.keys()) {
|
||||
_settings.setValue(key, map.value(key));
|
||||
}
|
||||
_settings.endGroup();
|
||||
}
|
||||
|
||||
QVariantMap ImageWriter::getSavedCustomizationSettings()
|
||||
{
|
||||
QVariantMap result;
|
||||
|
||||
_settings.beginGroup("imagecustomization");
|
||||
for (QString key : _settings.childKeys()) {
|
||||
result.insert(key, _settings.value(key));
|
||||
}
|
||||
_settings.endGroup();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void ImageWriter::clearSavedCustomizationSettings()
|
||||
{
|
||||
_settings.beginGroup("imagecustomization");
|
||||
_settings.remove("");
|
||||
_settings.endGroup();
|
||||
}
|
||||
|
||||
bool ImageWriter::hasSavedCustomizationSettings()
|
||||
{
|
||||
_settings.beginGroup("imagecustomization");
|
||||
bool result = !_settings.childKeys().isEmpty();
|
||||
_settings.endGroup();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void MountUtilsLog(std::string msg) {
|
||||
qDebug() << "mountutils:" << msg.c_str();
|
||||
}
|
||||
|
|
|
@ -103,6 +103,10 @@ public:
|
|||
Q_INVOKABLE bool getBoolSetting(const QString &key);
|
||||
Q_INVOKABLE void setSetting(const QString &key, const QVariant &value);
|
||||
Q_INVOKABLE void setImageCustomization(const QByteArray &config, const QByteArray &cmdline, const QByteArray &firstrun);
|
||||
Q_INVOKABLE void setSavedCustomizationSettings(const QVariantMap &map);
|
||||
Q_INVOKABLE QVariantMap getSavedCustomizationSettings();
|
||||
Q_INVOKABLE void clearSavedCustomizationSettings();
|
||||
Q_INVOKABLE bool hasSavedCustomizationSettings();
|
||||
|
||||
Q_INVOKABLE QString crypt(const QByteArray &password);
|
||||
|
||||
|
|
25
main.qml
25
main.qml
|
@ -188,11 +188,16 @@ ApplicationWindow {
|
|||
Material.background: "#ffffff"
|
||||
Material.foreground: "#c51a4a"
|
||||
onClicked: {
|
||||
if (!imageWriter.readyToWrite())
|
||||
return;
|
||||
if (!imageWriter.readyToWrite()) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!optionspopup.initialized && imageWriter.hasSavedCustomizationSettings()) {
|
||||
usesavedsettingspopup.openPopup()
|
||||
} else {
|
||||
confirmwritepopup.askForConfirmation()
|
||||
}
|
||||
}
|
||||
Accessible.onPressAction: clicked()
|
||||
}
|
||||
}
|
||||
|
@ -790,6 +795,22 @@ ApplicationWindow {
|
|||
id: optionspopup
|
||||
}
|
||||
|
||||
UseSavedSettingsPopup {
|
||||
id: usesavedsettingspopup
|
||||
onYes: {
|
||||
optionspopup.initialize()
|
||||
optionspopup.applySettings()
|
||||
confirmwritepopup.askForConfirmation()
|
||||
}
|
||||
onNo: {
|
||||
imageWriter.clearSavedCustomizationSettings()
|
||||
confirmwritepopup.askForConfirmation()
|
||||
}
|
||||
onEditSettings: {
|
||||
optionspopup.openPopup()
|
||||
}
|
||||
}
|
||||
|
||||
/* Utility functions */
|
||||
function httpRequest(url, callback) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
|
|
1
qml.qrc
1
qml.qrc
|
@ -25,5 +25,6 @@
|
|||
<file>OptionsPopup.qml</file>
|
||||
<file>countries.txt</file>
|
||||
<file>timezones.txt</file>
|
||||
<file>UseSavedSettingsPopup.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue