2024-06-24 18:49:23 -04:00
|
|
|
import QtCore
|
|
|
|
import QtQuick
|
|
|
|
import QtQuick.Controls
|
|
|
|
import QtQuick.Controls.Basic
|
|
|
|
import QtQuick.Layouts
|
|
|
|
import QtQuick.Dialogs
|
|
|
|
import Qt.labs.folderlistmodel
|
|
|
|
import Qt5Compat.GraphicalEffects
|
|
|
|
import llm
|
|
|
|
import chatlistmodel
|
|
|
|
import download
|
|
|
|
import modellist
|
|
|
|
import network
|
|
|
|
import gpt4all
|
|
|
|
import mysettings
|
|
|
|
import localdocs
|
|
|
|
|
|
|
|
Rectangle {
|
|
|
|
id: addModelView
|
|
|
|
|
|
|
|
Theme {
|
|
|
|
id: theme
|
|
|
|
}
|
|
|
|
|
|
|
|
color: theme.viewBackground
|
|
|
|
signal modelsViewRequested()
|
|
|
|
|
|
|
|
PopupDialog {
|
|
|
|
id: downloadingErrorPopup
|
|
|
|
anchors.centerIn: parent
|
|
|
|
shouldTimeOut: false
|
|
|
|
}
|
|
|
|
|
|
|
|
ColumnLayout {
|
|
|
|
id: mainArea
|
|
|
|
anchors.left: parent.left
|
|
|
|
anchors.right: parent.right
|
|
|
|
anchors.top: parent.top
|
|
|
|
anchors.bottom: parent.bottom
|
|
|
|
anchors.margins: 30
|
2024-06-26 13:00:01 -04:00
|
|
|
spacing: 30
|
2024-06-24 18:49:23 -04:00
|
|
|
|
|
|
|
ColumnLayout {
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.alignment: Qt.AlignTop
|
2024-06-26 13:00:01 -04:00
|
|
|
spacing: 30
|
2024-06-24 18:49:23 -04:00
|
|
|
|
|
|
|
MyButton {
|
|
|
|
id: backButton
|
|
|
|
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
|
|
|
|
text: qsTr("\u2190 Existing Models")
|
|
|
|
|
|
|
|
borderWidth: 0
|
|
|
|
backgroundColor: theme.lighterButtonBackground
|
|
|
|
backgroundColorHovered: theme.lighterButtonBackgroundHovered
|
|
|
|
backgroundRadius: 5
|
|
|
|
padding: 15
|
|
|
|
topPadding: 8
|
|
|
|
bottomPadding: 8
|
|
|
|
textColor: theme.lighterButtonForeground
|
|
|
|
fontPixelSize: theme.fontSizeLarge
|
|
|
|
fontPixelBold: true
|
|
|
|
|
|
|
|
onClicked: {
|
|
|
|
modelsViewRequested()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Text {
|
|
|
|
id: welcome
|
|
|
|
text: qsTr("Explore Models")
|
|
|
|
font.pixelSize: theme.fontSizeBanner
|
|
|
|
color: theme.titleTextColor
|
|
|
|
}
|
|
|
|
|
|
|
|
RowLayout {
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.alignment: Qt.AlignCenter
|
|
|
|
Layout.margins: 0
|
|
|
|
spacing: 10
|
|
|
|
MyTextField {
|
|
|
|
id: discoverField
|
|
|
|
property string textBeingSearched: ""
|
|
|
|
readOnly: ModelList.discoverInProgress
|
|
|
|
Layout.alignment: Qt.AlignCenter
|
|
|
|
Layout.fillWidth: true
|
|
|
|
font.pixelSize: theme.fontSizeLarger
|
|
|
|
placeholderText: qsTr("Discover and download models by keyword search...")
|
|
|
|
Accessible.role: Accessible.EditableText
|
|
|
|
Accessible.name: placeholderText
|
|
|
|
Accessible.description: qsTr("Text field for discovering and filtering downloadable models")
|
|
|
|
Connections {
|
|
|
|
target: ModelList
|
|
|
|
function onDiscoverInProgressChanged() {
|
|
|
|
if (ModelList.discoverInProgress) {
|
|
|
|
discoverField.textBeingSearched = discoverField.text;
|
|
|
|
discoverField.text = qsTr("Searching \u00B7 ") + discoverField.textBeingSearched;
|
|
|
|
} else {
|
|
|
|
discoverField.text = discoverField.textBeingSearched;
|
|
|
|
discoverField.textBeingSearched = "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
background: ProgressBar {
|
|
|
|
id: discoverProgressBar
|
|
|
|
indeterminate: ModelList.discoverInProgress && ModelList.discoverProgress === 0.0
|
|
|
|
value: ModelList.discoverProgress
|
|
|
|
background: Rectangle {
|
|
|
|
color: theme.controlBackground
|
|
|
|
border.color: theme.controlBorder
|
|
|
|
radius: 10
|
|
|
|
}
|
|
|
|
contentItem: Item {
|
|
|
|
Rectangle {
|
|
|
|
visible: ModelList.discoverInProgress
|
|
|
|
anchors.bottom: parent.bottom
|
|
|
|
width: discoverProgressBar.visualPosition * parent.width
|
|
|
|
height: 10
|
|
|
|
radius: 2
|
|
|
|
color: theme.progressForeground
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Keys.onReturnPressed: (event)=> {
|
|
|
|
if (event.modifiers & Qt.ControlModifier || event.modifiers & Qt.ShiftModifier)
|
|
|
|
event.accepted = false;
|
|
|
|
else {
|
|
|
|
editingFinished();
|
|
|
|
sendDiscovery()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function sendDiscovery() {
|
|
|
|
ModelList.downloadableModels.discoverAndFilter(discoverField.text);
|
|
|
|
}
|
|
|
|
RowLayout {
|
|
|
|
spacing: 0
|
|
|
|
anchors.right: discoverField.right
|
|
|
|
anchors.verticalCenter: discoverField.verticalCenter
|
|
|
|
anchors.rightMargin: 15
|
|
|
|
visible: !ModelList.discoverInProgress
|
|
|
|
MyMiniButton {
|
|
|
|
id: clearDiscoverButton
|
|
|
|
backgroundColor: theme.textColor
|
|
|
|
backgroundColorHovered: theme.iconBackgroundDark
|
|
|
|
visible: discoverField.text !== ""
|
|
|
|
contentItem: Text {
|
|
|
|
color: clearDiscoverButton.hovered ? theme.iconBackgroundDark : theme.textColor
|
|
|
|
text: "\u2715"
|
|
|
|
font.pixelSize: theme.fontSizeLarge
|
|
|
|
}
|
|
|
|
onClicked: {
|
|
|
|
discoverField.text = ""
|
|
|
|
discoverField.sendDiscovery() // should clear results
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MyMiniButton {
|
|
|
|
backgroundColor: theme.textColor
|
|
|
|
backgroundColorHovered: theme.iconBackgroundDark
|
|
|
|
source: "qrc:/gpt4all/icons/settings.svg"
|
|
|
|
onClicked: {
|
|
|
|
discoveryTools.visible = !discoveryTools.visible
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MyMiniButton {
|
|
|
|
id: sendButton
|
|
|
|
enabled: !ModelList.discoverInProgress
|
|
|
|
backgroundColor: theme.textColor
|
|
|
|
backgroundColorHovered: theme.iconBackgroundDark
|
|
|
|
source: "qrc:/gpt4all/icons/send_message.svg"
|
|
|
|
Accessible.name: qsTr("Initiate model discovery and filtering")
|
|
|
|
Accessible.description: qsTr("Triggers discovery and filtering of models")
|
|
|
|
onClicked: {
|
|
|
|
discoverField.sendDiscovery()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RowLayout {
|
|
|
|
id: discoveryTools
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.alignment: Qt.AlignCenter
|
|
|
|
Layout.margins: 0
|
|
|
|
spacing: 20
|
|
|
|
visible: false
|
|
|
|
MyComboBox {
|
|
|
|
id: comboSort
|
|
|
|
model: [qsTr("Default"), qsTr("Likes"), qsTr("Downloads"), qsTr("Recent")]
|
|
|
|
currentIndex: ModelList.discoverSort
|
|
|
|
contentItem: Text {
|
|
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
|
|
rightPadding: 30
|
|
|
|
color: theme.textColor
|
|
|
|
text: {
|
|
|
|
return qsTr("Sort by: ") + comboSort.displayText
|
|
|
|
}
|
|
|
|
font.pixelSize: theme.fontSizeLarger
|
|
|
|
verticalAlignment: Text.AlignVCenter
|
|
|
|
horizontalAlignment: Text.AlignHCenter
|
|
|
|
elide: Text.ElideRight
|
|
|
|
}
|
|
|
|
onActivated: function (index) {
|
|
|
|
ModelList.discoverSort = index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MyComboBox {
|
|
|
|
id: comboSortDirection
|
|
|
|
model: [qsTr("Asc"), qsTr("Desc")]
|
|
|
|
currentIndex: {
|
|
|
|
if (ModelList.discoverSortDirection === 1)
|
|
|
|
return 0
|
|
|
|
else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
contentItem: Text {
|
|
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
|
|
rightPadding: 30
|
|
|
|
color: theme.textColor
|
|
|
|
text: {
|
|
|
|
return qsTr("Sort dir: ") + comboSortDirection.displayText
|
|
|
|
}
|
|
|
|
font.pixelSize: theme.fontSizeLarger
|
|
|
|
verticalAlignment: Text.AlignVCenter
|
|
|
|
horizontalAlignment: Text.AlignHCenter
|
|
|
|
elide: Text.ElideRight
|
|
|
|
}
|
|
|
|
onActivated: function (index) {
|
|
|
|
if (index === 0)
|
|
|
|
ModelList.discoverSortDirection = 1;
|
|
|
|
else
|
|
|
|
ModelList.discoverSortDirection = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MyComboBox {
|
|
|
|
id: comboLimit
|
|
|
|
model: ["5", "10", "20", "50", "100", qsTr("None")]
|
|
|
|
currentIndex: {
|
|
|
|
if (ModelList.discoverLimit === 5)
|
|
|
|
return 0;
|
|
|
|
else if (ModelList.discoverLimit === 10)
|
|
|
|
return 1;
|
|
|
|
else if (ModelList.discoverLimit === 20)
|
|
|
|
return 2;
|
|
|
|
else if (ModelList.discoverLimit === 50)
|
|
|
|
return 3;
|
|
|
|
else if (ModelList.discoverLimit === 100)
|
|
|
|
return 4;
|
|
|
|
else if (ModelList.discoverLimit === -1)
|
|
|
|
return 5;
|
|
|
|
}
|
|
|
|
contentItem: Text {
|
|
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
|
|
rightPadding: 30
|
|
|
|
color: theme.textColor
|
|
|
|
text: {
|
|
|
|
return qsTr("Limit: ") + comboLimit.displayText
|
|
|
|
}
|
|
|
|
font.pixelSize: theme.fontSizeLarger
|
|
|
|
verticalAlignment: Text.AlignVCenter
|
|
|
|
horizontalAlignment: Text.AlignHCenter
|
|
|
|
elide: Text.ElideRight
|
|
|
|
}
|
|
|
|
onActivated: function (index) {
|
|
|
|
switch (index) {
|
|
|
|
case 0:
|
|
|
|
ModelList.discoverLimit = 5; break;
|
|
|
|
case 1:
|
|
|
|
ModelList.discoverLimit = 10; break;
|
|
|
|
case 2:
|
|
|
|
ModelList.discoverLimit = 20; break;
|
|
|
|
case 3:
|
|
|
|
ModelList.discoverLimit = 50; break;
|
|
|
|
case 4:
|
|
|
|
ModelList.discoverLimit = 100; break;
|
|
|
|
case 5:
|
|
|
|
ModelList.discoverLimit = -1; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Label {
|
|
|
|
visible: !ModelList.downloadableModels.count && !ModelList.asyncModelRequestOngoing
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.fillHeight: true
|
|
|
|
horizontalAlignment: Qt.AlignHCenter
|
|
|
|
verticalAlignment: Qt.AlignVCenter
|
|
|
|
text: qsTr("Network error: could not retrieve http://gpt4all.io/models/models3.json")
|
|
|
|
font.pixelSize: theme.fontSizeLarge
|
|
|
|
color: theme.mutedTextColor
|
|
|
|
}
|
|
|
|
|
|
|
|
MyBusyIndicator {
|
|
|
|
visible: !ModelList.downloadableModels.count && ModelList.asyncModelRequestOngoing
|
|
|
|
running: ModelList.asyncModelRequestOngoing
|
|
|
|
Accessible.role: Accessible.Animation
|
|
|
|
Layout.alignment: Qt.AlignCenter
|
|
|
|
Accessible.name: qsTr("Busy indicator")
|
|
|
|
Accessible.description: qsTr("Displayed when the models request is ongoing")
|
|
|
|
}
|
|
|
|
|
|
|
|
ScrollView {
|
|
|
|
id: scrollView
|
|
|
|
ScrollBar.vertical.policy: ScrollBar.AsNeeded
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.fillHeight: true
|
|
|
|
clip: true
|
|
|
|
|
|
|
|
ListView {
|
|
|
|
id: modelListView
|
|
|
|
model: ModelList.downloadableModels
|
|
|
|
boundsBehavior: Flickable.StopAtBounds
|
|
|
|
spacing: 30
|
|
|
|
|
|
|
|
delegate: Rectangle {
|
|
|
|
id: delegateItem
|
|
|
|
width: modelListView.width
|
|
|
|
height: childrenRect.height + 60
|
|
|
|
color: theme.conversationBackground
|
|
|
|
radius: 10
|
|
|
|
border.width: 1
|
|
|
|
border.color: theme.controlBorder
|
|
|
|
|
|
|
|
ColumnLayout {
|
|
|
|
anchors.top: parent.top
|
|
|
|
anchors.left: parent.left
|
|
|
|
anchors.right: parent.right
|
|
|
|
anchors.margins: 30
|
|
|
|
|
|
|
|
Text {
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.alignment: Qt.AlignLeft
|
|
|
|
text: name
|
|
|
|
elide: Text.ElideRight
|
|
|
|
color: theme.titleTextColor
|
|
|
|
font.pixelSize: theme.fontSizeLargest
|
|
|
|
font.bold: true
|
|
|
|
Accessible.role: Accessible.Paragraph
|
|
|
|
Accessible.name: qsTr("Model file")
|
|
|
|
Accessible.description: qsTr("Model file to be downloaded")
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Rectangle {
|
|
|
|
Layout.fillWidth: true
|
|
|
|
height: 1
|
|
|
|
color: theme.dividerColor
|
|
|
|
}
|
|
|
|
|
|
|
|
RowLayout {
|
|
|
|
Layout.topMargin: 10
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Text {
|
|
|
|
id: descriptionText
|
|
|
|
text: description
|
|
|
|
font.pixelSize: theme.fontSizeLarge
|
|
|
|
Layout.fillWidth: true
|
|
|
|
wrapMode: Text.WordWrap
|
|
|
|
textFormat: Text.StyledText
|
|
|
|
color: theme.textColor
|
|
|
|
linkColor: theme.textColor
|
|
|
|
Accessible.role: Accessible.Paragraph
|
|
|
|
Accessible.name: qsTr("Description")
|
|
|
|
Accessible.description: qsTr("File description")
|
|
|
|
onLinkActivated: Qt.openUrlExternally(link)
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME Need to overhaul design here which must take into account
|
|
|
|
// features not present in current figma including:
|
|
|
|
// * Ability to cancel a current download
|
|
|
|
// * Ability to resume a download
|
|
|
|
// * The presentation of an error if encountered
|
|
|
|
// * Whether to show already installed models
|
|
|
|
// * Install of remote models with API keys
|
|
|
|
// * The presentation of the progress bar
|
|
|
|
Rectangle {
|
|
|
|
id: actionBox
|
|
|
|
width: childrenRect.width + 20
|
|
|
|
color: "transparent"
|
|
|
|
border.width: 1
|
|
|
|
border.color: theme.dividerColor
|
|
|
|
radius: 10
|
|
|
|
Layout.rightMargin: 20
|
|
|
|
Layout.bottomMargin: 20
|
|
|
|
Layout.minimumHeight: childrenRect.height + 20
|
|
|
|
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
|
|
|
|
|
|
|
ColumnLayout {
|
|
|
|
spacing: 0
|
|
|
|
MySettingsButton {
|
|
|
|
id: downloadButton
|
|
|
|
text: isDownloading ? qsTr("Cancel") : isIncomplete ? qsTr("Resume") : qsTr("Download")
|
|
|
|
font.pixelSize: theme.fontSizeLarge
|
|
|
|
Layout.topMargin: 20
|
|
|
|
Layout.leftMargin: 20
|
|
|
|
Layout.minimumWidth: 200
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
|
|
|
visible: !isOnline && !installed && !calcHash && downloadError === ""
|
|
|
|
Accessible.description: qsTr("Stop/restart/start the download")
|
|
|
|
onClicked: {
|
|
|
|
if (!isDownloading) {
|
|
|
|
Download.downloadModel(filename);
|
|
|
|
} else {
|
|
|
|
Download.cancelDownload(filename);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MySettingsDestructiveButton {
|
|
|
|
id: removeButton
|
|
|
|
text: qsTr("Remove")
|
|
|
|
Layout.topMargin: 20
|
|
|
|
Layout.leftMargin: 20
|
|
|
|
Layout.minimumWidth: 200
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
|
|
|
visible: installed || downloadError !== ""
|
|
|
|
Accessible.description: qsTr("Remove model from filesystem")
|
|
|
|
onClicked: {
|
|
|
|
Download.removeModel(filename);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MySettingsButton {
|
|
|
|
id: installButton
|
|
|
|
visible: !installed && isOnline
|
|
|
|
Layout.topMargin: 20
|
|
|
|
Layout.leftMargin: 20
|
|
|
|
Layout.minimumWidth: 200
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
|
|
|
text: qsTr("Install")
|
|
|
|
font.pixelSize: theme.fontSizeLarge
|
|
|
|
onClicked: {
|
|
|
|
if (apiKey.text === "")
|
|
|
|
apiKey.showError();
|
|
|
|
else
|
|
|
|
Download.installModel(filename, apiKey.text);
|
|
|
|
}
|
|
|
|
Accessible.role: Accessible.Button
|
|
|
|
Accessible.name: qsTr("Install")
|
|
|
|
Accessible.description: qsTr("Install online model")
|
|
|
|
}
|
|
|
|
|
|
|
|
ColumnLayout {
|
|
|
|
spacing: 0
|
|
|
|
Label {
|
|
|
|
Layout.topMargin: 20
|
|
|
|
Layout.leftMargin: 20
|
|
|
|
visible: downloadError !== ""
|
|
|
|
textFormat: Text.StyledText
|
|
|
|
text: "<strong><font size=\"1\">"
|
|
|
|
+ qsTr("<a href=\"#error\">Error</a>")
|
|
|
|
+ "</strong></font>"
|
|
|
|
color: theme.textColor
|
|
|
|
font.pixelSize: theme.fontSizeLarge
|
|
|
|
linkColor: theme.textErrorColor
|
|
|
|
Accessible.role: Accessible.Paragraph
|
|
|
|
Accessible.name: text
|
|
|
|
Accessible.description: qsTr("Describes an error that occurred when downloading")
|
|
|
|
onLinkActivated: {
|
|
|
|
downloadingErrorPopup.text = downloadError;
|
|
|
|
downloadingErrorPopup.open();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Label {
|
|
|
|
visible: LLM.systemTotalRAMInGB() < ramrequired
|
|
|
|
Layout.topMargin: 20
|
|
|
|
Layout.leftMargin: 20
|
|
|
|
Layout.maximumWidth: 300
|
|
|
|
textFormat: Text.StyledText
|
|
|
|
text: qsTr("<strong><font size=\"2\">WARNING: Not recommended for your hardware.")
|
|
|
|
+ qsTr(" Model requires more memory (") + ramrequired
|
|
|
|
+ qsTr(" GB) than your system has available (")
|
|
|
|
+ LLM.systemTotalRAMInGBString() + ").</strong></font>"
|
|
|
|
color: theme.textErrorColor
|
|
|
|
font.pixelSize: theme.fontSizeLarge
|
|
|
|
wrapMode: Text.WordWrap
|
|
|
|
Accessible.role: Accessible.Paragraph
|
|
|
|
Accessible.name: text
|
|
|
|
Accessible.description: qsTr("Error for incompatible hardware")
|
|
|
|
onLinkActivated: {
|
|
|
|
downloadingErrorPopup.text = downloadError;
|
|
|
|
downloadingErrorPopup.open();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ColumnLayout {
|
|
|
|
visible: isDownloading && !calcHash
|
|
|
|
Layout.topMargin: 20
|
|
|
|
Layout.leftMargin: 20
|
|
|
|
Layout.minimumWidth: 200
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
|
|
|
spacing: 20
|
|
|
|
|
|
|
|
ProgressBar {
|
|
|
|
id: itemProgressBar
|
|
|
|
Layout.fillWidth: true
|
|
|
|
width: 200
|
|
|
|
value: bytesReceived / bytesTotal
|
|
|
|
background: Rectangle {
|
|
|
|
implicitHeight: 45
|
|
|
|
color: theme.progressBackground
|
|
|
|
radius: 3
|
|
|
|
}
|
|
|
|
contentItem: Item {
|
|
|
|
implicitHeight: 40
|
|
|
|
|
|
|
|
Rectangle {
|
|
|
|
width: itemProgressBar.visualPosition * parent.width
|
|
|
|
height: parent.height
|
|
|
|
radius: 2
|
|
|
|
color: theme.progressForeground
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Accessible.role: Accessible.ProgressBar
|
|
|
|
Accessible.name: qsTr("Download progressBar")
|
|
|
|
Accessible.description: qsTr("Shows the progress made in the download")
|
|
|
|
}
|
|
|
|
|
|
|
|
Label {
|
|
|
|
id: speedLabel
|
|
|
|
color: theme.textColor
|
|
|
|
Layout.alignment: Qt.AlignRight
|
|
|
|
text: speed
|
|
|
|
font.pixelSize: theme.fontSizeLarge
|
|
|
|
Accessible.role: Accessible.Paragraph
|
|
|
|
Accessible.name: qsTr("Download speed")
|
|
|
|
Accessible.description: qsTr("Download speed in bytes/kilobytes/megabytes per second")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RowLayout {
|
|
|
|
visible: calcHash
|
|
|
|
Layout.topMargin: 20
|
|
|
|
Layout.leftMargin: 20
|
|
|
|
Layout.minimumWidth: 200
|
|
|
|
Layout.maximumWidth: 200
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
|
|
|
clip: true
|
|
|
|
|
|
|
|
Label {
|
|
|
|
id: calcHashLabel
|
|
|
|
color: theme.textColor
|
|
|
|
text: qsTr("Calculating...")
|
|
|
|
font.pixelSize: theme.fontSizeLarge
|
|
|
|
Accessible.role: Accessible.Paragraph
|
|
|
|
Accessible.name: text
|
|
|
|
Accessible.description: qsTr("Whether the file hash is being calculated")
|
|
|
|
}
|
|
|
|
|
|
|
|
MyBusyIndicator {
|
|
|
|
id: busyCalcHash
|
|
|
|
running: calcHash
|
|
|
|
Accessible.role: Accessible.Animation
|
|
|
|
Accessible.name: qsTr("Busy indicator")
|
|
|
|
Accessible.description: qsTr("Displayed when the file hash is being calculated")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MyTextField {
|
|
|
|
id: apiKey
|
|
|
|
visible: !installed && isOnline
|
|
|
|
Layout.topMargin: 20
|
|
|
|
Layout.leftMargin: 20
|
|
|
|
Layout.minimumWidth: 200
|
|
|
|
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
|
|
|
wrapMode: Text.WrapAnywhere
|
|
|
|
function showError() {
|
|
|
|
apiKey.placeholderTextColor = theme.textErrorColor
|
|
|
|
}
|
|
|
|
onTextChanged: {
|
|
|
|
apiKey.placeholderTextColor = theme.mutedTextColor
|
|
|
|
}
|
|
|
|
placeholderText: qsTr("enter $API_KEY")
|
|
|
|
Accessible.role: Accessible.EditableText
|
|
|
|
Accessible.name: placeholderText
|
|
|
|
Accessible.description: qsTr("Whether the file hash is being calculated")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Item {
|
|
|
|
Layout.minimumWidth: childrenRect.width
|
|
|
|
Layout.minimumHeight: childrenRect.height
|
|
|
|
Layout.bottomMargin: 10
|
|
|
|
RowLayout {
|
|
|
|
id: paramRow
|
|
|
|
anchors.centerIn: parent
|
|
|
|
ColumnLayout {
|
|
|
|
Layout.topMargin: 10
|
|
|
|
Layout.bottomMargin: 10
|
|
|
|
Layout.leftMargin: 20
|
|
|
|
Layout.rightMargin: 20
|
|
|
|
Text {
|
|
|
|
text: qsTr("File size")
|
|
|
|
font.pixelSize: theme.fontSizeSmaller
|
|
|
|
color: theme.mutedDarkTextColor
|
|
|
|
}
|
|
|
|
Text {
|
|
|
|
text: filesize
|
|
|
|
color: theme.textColor
|
|
|
|
font.pixelSize: theme.fontSizeSmaller
|
|
|
|
font.bold: true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Rectangle {
|
|
|
|
width: 1
|
|
|
|
Layout.fillHeight: true
|
|
|
|
color: theme.dividerColor
|
|
|
|
}
|
|
|
|
ColumnLayout {
|
|
|
|
Layout.topMargin: 10
|
|
|
|
Layout.bottomMargin: 10
|
|
|
|
Layout.leftMargin: 20
|
|
|
|
Layout.rightMargin: 20
|
|
|
|
Text {
|
|
|
|
text: qsTr("RAM required")
|
|
|
|
font.pixelSize: theme.fontSizeSmaller
|
|
|
|
color: theme.mutedDarkTextColor
|
|
|
|
}
|
|
|
|
Text {
|
2024-06-26 12:31:11 -04:00
|
|
|
text: ramrequired >= 0 ? ramrequired + qsTr(" GB") : "?"
|
2024-06-24 18:49:23 -04:00
|
|
|
color: theme.textColor
|
|
|
|
font.pixelSize: theme.fontSizeSmaller
|
|
|
|
font.bold: true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Rectangle {
|
|
|
|
width: 1
|
|
|
|
Layout.fillHeight: true
|
|
|
|
color: theme.dividerColor
|
|
|
|
}
|
|
|
|
ColumnLayout {
|
|
|
|
Layout.topMargin: 10
|
|
|
|
Layout.bottomMargin: 10
|
|
|
|
Layout.leftMargin: 20
|
|
|
|
Layout.rightMargin: 20
|
|
|
|
Text {
|
|
|
|
text: qsTr("Parameters")
|
|
|
|
font.pixelSize: theme.fontSizeSmaller
|
|
|
|
color: theme.mutedDarkTextColor
|
|
|
|
}
|
|
|
|
Text {
|
2024-06-26 12:31:11 -04:00
|
|
|
text: parameters !== "" ? parameters : "?"
|
2024-06-24 18:49:23 -04:00
|
|
|
color: theme.textColor
|
|
|
|
font.pixelSize: theme.fontSizeSmaller
|
|
|
|
font.bold: true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Rectangle {
|
|
|
|
width: 1
|
|
|
|
Layout.fillHeight: true
|
|
|
|
color: theme.dividerColor
|
|
|
|
}
|
|
|
|
ColumnLayout {
|
|
|
|
Layout.topMargin: 10
|
|
|
|
Layout.bottomMargin: 10
|
|
|
|
Layout.leftMargin: 20
|
|
|
|
Layout.rightMargin: 20
|
|
|
|
Text {
|
|
|
|
text: qsTr("Quant")
|
|
|
|
font.pixelSize: theme.fontSizeSmaller
|
|
|
|
color: theme.mutedDarkTextColor
|
|
|
|
}
|
|
|
|
Text {
|
|
|
|
text: quant
|
|
|
|
color: theme.textColor
|
|
|
|
font.pixelSize: theme.fontSizeSmaller
|
|
|
|
font.bold: true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Rectangle {
|
|
|
|
width: 1
|
|
|
|
Layout.fillHeight: true
|
|
|
|
color: theme.dividerColor
|
|
|
|
}
|
|
|
|
ColumnLayout {
|
|
|
|
Layout.topMargin: 10
|
|
|
|
Layout.bottomMargin: 10
|
|
|
|
Layout.leftMargin: 20
|
|
|
|
Layout.rightMargin: 20
|
|
|
|
Text {
|
|
|
|
text: qsTr("Type")
|
|
|
|
font.pixelSize: theme.fontSizeSmaller
|
|
|
|
color: theme.mutedDarkTextColor
|
|
|
|
}
|
|
|
|
Text {
|
|
|
|
text: type
|
|
|
|
color: theme.textColor
|
|
|
|
font.pixelSize: theme.fontSizeSmaller
|
|
|
|
font.bold: true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Rectangle {
|
|
|
|
color: "transparent"
|
|
|
|
anchors.fill: paramRow
|
|
|
|
border.color: theme.dividerColor
|
|
|
|
border.width: 1
|
|
|
|
radius: 10
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Rectangle {
|
|
|
|
Layout.fillWidth: true
|
|
|
|
height: 1
|
|
|
|
color: theme.dividerColor
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|