Update avatar packager styling

This commit is contained in:
Ryan Huffman 2018-12-27 00:13:45 -08:00
parent 8c56e35f69
commit 1da179dc04
12 changed files with 368 additions and 61 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

View file

@ -48,6 +48,7 @@ Windows.ScrollingWindow {
id: popup
anchors.fill: parent
visible: false
closeOnClickOutside: true
}
Column {

View file

@ -19,35 +19,130 @@ Item {
property int colorScheme;
property var uploader: undefined;
property bool hasSuccessfullyUploaded: true;
visible: false
anchors.fill: parent
anchors.margins: 10
property var footer: Item {
id: uploadFooter
anchors.fill: parent
anchors.rightMargin: 17
HifiControls.Button {
id: uploadButton
enabled: Account.loggedIn
//width: parent.width
//anchors.bottom: parent.bottom
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
text: qsTr("Upload")
color: hifi.buttons.blue
colorScheme: root.colorScheme
width: 133
height: 40
onClicked: function() {
if (AvatarPackagerCore.currentAvatarProject.fst.hasMarketplaceID()) {
showConfirmUploadPopup(uploadNew, uploadUpdate);
} else {
Item {
id: uploadFooter
visible: !root.uploader || root.finished || root.uploader.state !== 4
anchors.fill: parent
anchors.rightMargin: 17
HifiControls.Button {
id: uploadButton
visible: !AvatarPackagerCore.currentAvatarProject.fst.hasMarketplaceID && !root.hasSuccessfullyUploaded
enabled: Account.loggedIn
//width: parent.width
//anchors.bottom: parent.bottom
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
text: qsTr("Upload")
color: hifi.buttons.blue
colorScheme: root.colorScheme
width: 133
height: 40
onClicked: function() {
uploadNew();
}
}
HifiControls.Button {
id: updateButton
visible: AvatarPackagerCore.currentAvatarProject.fst.hasMarketplaceID && !root.hasSuccessfullyUploaded
enabled: Account.loggedIn
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
text: qsTr("Update")
color: hifi.buttons.blue
colorScheme: root.colorScheme
width: 134
height: 40
onClicked: function() {
showConfirmUploadPopup(uploadNew, uploadUpdate);
}
}
Item {
anchors.fill: parent
visible: root.hasSuccessfullyUploaded
HifiControls.Button {
enabled: Account.loggedIn
anchors.verticalCenter: parent.verticalCenter
anchors.right: viewInInventoryButton.left
anchors.rightMargin: 16
text: qsTr("Update")
color: hifi.buttons.white
colorScheme: root.colorScheme
width: 134
height: 40
onClicked: function() {
showConfirmUploadPopup(uploadNew, uploadUpdate);
}
}
HifiControls.Button {
id: viewInInventoryButton
enabled: Account.loggedIn
width: 168
height: 40
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
text: qsTr("View in Inventory")
color: hifi.buttons.blue
colorScheme: root.colorScheme
onClicked: AvatarPackagerCore.currentAvatarProject.openInInventory()
}
}
}
Rectangle {
id: uploadingItemFooter
anchors.fill: parent
anchors.topMargin: 1
visible: !!root.uploader && !root.finished && root.uploader.state === 4
color: "#00B4EF"
LoadingCircle {
id: runningImage
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 16
width: 28
height: 28
}
RalewayRegular {
id: stepText
size: 20
anchors.verticalCenter: parent.verticalCenter
anchors.left: runningImage.right
anchors.leftMargin: 16
text: "Adding item to Inventory"
color: "white"
}
}
}
@ -66,7 +161,10 @@ Item {
root.uploader.uploadProgress.connect(function(uploaded, total) {
console.log("Uploader progress: " + uploaded + " / " + total);
});
root.uploader.finished.connect(function() {
root.uploader.completed.connect(function() {
root.hasSuccessfullyUploaded = true;
});
root.uploader.finishedChanged.connect(function() {
try {
var response = JSON.parse(root.uploader.responseData);
console.log("Uploader complete! " + response);
@ -121,6 +219,25 @@ Item {
RalewayRegular {
id: infoMessage
states: [
State {
when: root.hasSuccessfullyUploaded
name: "upload-success"
PropertyChanges {
target: infoMessage
text: "Your avatar has been uploaded to our servers. You can modify the project files and update it again to make changes on the uploaded avatar."
}
},
State {
name: "has-previous-success"
when: !!AvatarPackagerCore.currentAvatarProject && AvatarPackagerCore.currentAvatarProject.fst.hasMarketplaceID
PropertyChanges {
target: infoMessage
text: "Click \"Update\" to overwrite the hosted files and update the avatar in your inventory. You will have to “Wear” the avatar again to see changes."
}
}
]
color: 'white'
size: 20
@ -132,7 +249,7 @@ Item {
wrapMode: Text.Wrap
text: "Click \"Update\" to overwrite the hosted files and update the avatar in your inventory. You will have to “Wear” the avatar again to see changes."
text: "You can upload your files to our servers to always access them, and to make your avatar visible to other users."
}
HifiControls.Button {

View file

@ -8,28 +8,35 @@ import QtQuick.Controls 2.2 as Original
import "../../controlsUit" 1.0 as HifiControls
import "../../stylesUit" 1.0
Item {
id: uploadingScreen
property var root: undefined
//visible: !!root.uploader
visible: false
anchors.fill: parent
Timer {
id: backToProjectTimer
interval: 2000
interval: 5000
running: false
repeat: false
onTriggered: avatarPackager.state = "project"
onTriggered: {
if (avatarPackager.state =="project-upload") {
avatarPackager.state = "project"
}
}
}
function stateChangedCallback(newState) {
if (newState >= 4) {
root.uploader.stateChanged.disconnect(stateChangedCallback)
backToProjectTimer.start();
}
}
onVisibleChanged: {
console.log("Visibility changed");
if (visible) {
root.uploader.finished.connect(function() {
console.log("Did complete");
root.uploader.stateChanged.connect(stateChangedCallback);
root.uploader.finishedChanged.connect(function() {
backToProjectTimer.start();
});
}
@ -46,48 +53,62 @@ Item {
id: statusItem
width: parent.width
height: 128
height: 192
AnimatedImage {
states: [
State {
name: "success"
when: !!root.uploader && root.uploader.state >= 4 && root.uploader.error === 0
PropertyChanges { target: uploadSpinner; visible: false }
PropertyChanges { target: errorIcon; visible: false }
PropertyChanges { target: successIcon; visible: true }
},
State {
name: "error"
when: !!root.uploader && root.uploader.finished && root.uploader.error !== 0
PropertyChanges { target: uploadSpinner; visible: false }
PropertyChanges { target: errorIcon; visible: true }
PropertyChanges { target: successIcon; visible: false }
}
]
LoadingCircle {
id: uploadSpinner
visible: !!root.uploader && !root.uploader.complete
visible: true
anchors {
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
}
source: "../../../icons/loader-snake-64-w.gif"
playing: true
z: 10000
}
HiFiGlyphs {
id: errorIcon
visible: !!root.uploader && root.uploader.complete && root.uploader.error !== 0
visible: false
anchors {
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
}
size: 128
size: 164
text: "w"
color: "red"
color: "#EA4C5F"
}
HiFiGlyphs {
id: successIcon
visible: !!root.uploader && root.uploader.complete && root.uploader.error === 0
visible: false
anchors {
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
}
size: 128
size: 164
text: "\ue01a"
color: "#1FC6A6"
}
@ -96,34 +117,49 @@ Item {
id: statusRows
anchors.top: statusItem.bottom
anchors.left: parent.left
anchors.leftMargin: 12
AvatarUploadStatusItem {
id: statusCategories
uploader: root.uploader
text: "Retreiving categories"
state: root.uploader.state == 1 ? "running" : (root.uploader.state > 1 ? "success" : (root.uploader.error ? "fail" : ""))
uploaderState: 1
}
AvatarUploadStatusItem {
id: statusUploading
uploader: root.uploader
anchors.top: statusCategories.bottom
text: "Uploading data"
state: root.uploader.state == 2 ? "running" : (root.uploader.state > 2 ? "success" : (root.uploader.error ? "fail" : ""))
uploaderState: 2
}
// TODO add waiting for response
//AvatarUploadStatusItem {
//id: statusResponse
//text: "Waiting for completion"
//}
AvatarUploadStatusItem {
id: statusInventory
id: statusResponse
uploader: root.uploader
anchors.top: statusUploading.bottom
text: "Waiting for inventory"
text: "Waiting for response"
state: root.uploader.state == 3 ? "running" : (root.uploader.state > 3 ? "success" : (root.uploader.error ? "fail" : ""))
uploaderState: 3
}
}
RalewayRegular {
visible: root.uploader.error
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.leftMargin: 16
anchors.rightMargin: 16
anchors.bottomMargin: 16
size: 28
wrapMode: Text.Wrap
color: "white"
text: "We couldn't upload your avatar at this time. Please try again later."
}
}
Column {

View file

@ -0,0 +1,96 @@
import QtQuick 2.6
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import "../../controlsUit" 1.0 as HifiControls
import "../../stylesUit" 1.0
Item {
id: root
height: 48
property string text: "NO STEP TEXT"
property int uploaderState;
property var uploader;
state: root.uploader.state > uploaderState
? "success"
: (root.uploader.error !== 0 ? "fail" : (root.uploader.state === uploaderState ? "running" : ""))
states: [
State {
name: "running"
PropertyChanges { target: stepText; color: "white" }
PropertyChanges { target: runningImage; visible: true; playing: true }
},
State {
name: "fail"
PropertyChanges { target: stepText; color: "#EA4C5F" }
PropertyChanges { target: failGlyph; visible: true }
},
State {
name: "success"
PropertyChanges { target: stepText; color: "white" }
PropertyChanges { target: successGlyph; visible: true }
}
]
Item {
id: statusItem
width: 48
height: parent.height
AnimatedImage {
id: runningImage
visible: false
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
width: 32
height: 32
source: "../../../icons/loader-snake-64-w.gif"
playing: false
}
HiFiGlyphs {
id: successGlyph
visible: false
width: implicitWidth
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
size: 48
text: "\ue01a"
color: "#1FC6A6"
}
HiFiGlyphs {
id: failGlyph
visible: false
width: implicitWidth
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
size: 48
text: "+"
color: "#EA4C5F"
}
}
RalewayRegular {
id: stepText
anchors.left: statusItem.right
anchors.verticalCenter: parent.verticalCenter
text: root.text
size: 28
color: "#777777"
}
}

View file

@ -0,0 +1,20 @@
import QtQuick 2.6
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import QtGraphicalEffects 1.0
Image {
id: root
width: 128
height: 128
source: "../../../images/loader-snake-128.png"
RotationAnimation on rotation {
duration: 2000
loops: Animation.Infinite
from: 0
to: 360
}
}

View file

@ -23,6 +23,8 @@ Rectangle {
property string button2color: hifi.buttons.blue;
property string button2text: ''
property bool closeOnClickOutside: false;
property var onButton2Clicked;
property var onButton1Clicked;
property var onLinkClicked;
@ -56,6 +58,11 @@ Rectangle {
anchors.fill: parent;
propagateComposedEvents: false;
hoverEnabled: true;
onClicked: {
if (closeOnClickOutside) {
root.close()
}
}
}
Rectangle {
@ -68,6 +75,15 @@ Rectangle {
console.debug('mainContainer: height = ', height)
}
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
hoverEnabled: true;
onClicked: function(ev) {
ev.accepted = true;
}
}
anchors.centerIn: parent
color: "white"

View file

@ -34,7 +34,7 @@ class AvatarProject : public QObject {
Q_PROPERTY(QString projectFolderPath READ getProjectPath)
Q_PROPERTY(QString projectFSTPath READ getFSTPath)
Q_PROPERTY(QString projectFBXPath READ getFBXPath)
Q_PROPERTY(QString name READ getProjectName)
Q_PROPERTY(QString name READ getProjectName NOTIFY nameChanged)
public:
Q_INVOKABLE MarketplaceItemUploader* upload(bool updateExisting);
@ -57,6 +57,7 @@ public:
}
signals:
void nameChanged();
void projectFilesChanged();
private:

View file

@ -39,6 +39,8 @@ MarketplaceItemUploader::MarketplaceItemUploader(QString title,
}
void MarketplaceItemUploader::setState(State newState) {
Q_ASSERT(_state != State::Complete);
Q_ASSERT(_error == Error::None);
Q_ASSERT(newState != _state);
qDebug() << "Setting uploader state to: " << newState;
@ -46,16 +48,17 @@ void MarketplaceItemUploader::setState(State newState) {
emit stateChanged(newState);
if (newState == State::Complete) {
emit completed();
emit finished();
emit finishedChanged();
}
}
void MarketplaceItemUploader::setError(Error error) {
Q_ASSERT(_state != State::Complete);
Q_ASSERT(_error == Error::None);
_error = error;
emit errorChanged(error);
emit finished();
emit finishedChanged();
}
void MarketplaceItemUploader::send() {
@ -179,7 +182,6 @@ void MarketplaceItemUploader::doUploadAvatar() {
{ "description", _description },
{ "root_file_key", _rootFilename },
{ "category_ids", QJsonArray({ 5 }) },
//{ "attributions", QJsonArray({ QJsonObject{ { "name", "" }, { "link", "" } } }) },
{ "license", 0 },
{ "files", QString::fromLatin1(_fileData.toBase64()) } } } };
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
@ -197,14 +199,21 @@ void MarketplaceItemUploader::doUploadAvatar() {
reply = networkAccessManager.put(request, doc.toJson());
}
connect(reply, &QNetworkReply::uploadProgress, this, &MarketplaceItemUploader::uploadProgress);
connect(reply, &QNetworkReply::uploadProgress, this, [this](float bytesSent, float bytesTotal) {
if (_state == State::UploadingAvatar) {
emit uploadProgress(bytesSent, bytesTotal);
if (bytesSent >= bytesTotal) {
setState(State::WaitingForUploadResponse);
}
}
});
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
//_responseData = reply->readAll();
_responseData = reply->readAll();
qWarning() << "Finished request " << _responseData;
auto error = reply->error();
if (error == QNetworkReply::NoError) {
_responseData = reply->readAll();
qWarning() << "Finished request " << _responseData;
auto doc = QJsonDocument::fromJson(_responseData.toLatin1());
auto status = doc.object()["status"].toString();

View file

@ -21,6 +21,8 @@ class QNetworkReply;
class MarketplaceItemUploader : public QObject {
Q_OBJECT
Q_PROPERTY(bool finished READ getFinished NOTIFY finishedChanged)
Q_PROPERTY(bool complete READ getComplete NOTIFY stateChanged)
Q_PROPERTY(State state READ getState NOTIFY stateChanged)
Q_PROPERTY(Error error READ getError NOTIFY errorChanged)
@ -38,6 +40,7 @@ public:
Idle,
GettingCategories,
UploadingAvatar,
WaitingForUploadResponse,
WaitingForInventory,
Complete
};
@ -62,6 +65,7 @@ public:
QUuid getMarketplaceID() const { return _marketplaceID; }
Error getError() const { return _error; }
bool getFinished() const { return _state == State::Complete || _error != Error::None; }
signals:
void uploadProgress(qint64 bytesSent, qint64 bytesTotal);
@ -71,7 +75,7 @@ signals:
void errorChanged(Error error);
// Triggered when the upload has finished, either succesfully completing, or stopping with an error
void finished();
void finishedChanged();
private:
void doGetCategories();

View file

@ -175,3 +175,8 @@ bool FST::write() {
fst.write(FSTReader::writeMapping(getMapping()));
return true;
}
void FST::setMarketplaceID(QUuid marketplaceID) {
_marketplaceID = marketplaceID;
emit marketplaceIDChanged();
}

View file

@ -24,6 +24,7 @@ class FST : public QObject {
Q_PROPERTY(QString name READ getName WRITE setName NOTIFY nameChanged)
Q_PROPERTY(QString modelPath READ getModelPath WRITE setModelPath NOTIFY modelPathChanged)
Q_PROPERTY(QUuid marketplaceID READ getMarketplaceID)
Q_PROPERTY(bool hasMarketplaceID READ getHasMarketplaceID NOTIFY marketplaceIDChanged)
public:
FST(const QString& fstPath, QVariantHash data);
@ -37,9 +38,9 @@ public:
QString getModelPath() const { return _modelPath; }
void setModelPath(const QString& modelPath);
Q_INVOKABLE bool hasMarketplaceID() const { return !_marketplaceID.isNull(); }
Q_INVOKABLE bool getHasMarketplaceID() const { return !_marketplaceID.isNull(); }
QUuid getMarketplaceID() const { return _marketplaceID; }
void setMarketplaceID(QUuid marketplaceID) { _marketplaceID = marketplaceID; }
void setMarketplaceID(QUuid marketplaceID);
QStringList getScriptPaths() const { return _scriptPaths; }
void setScriptPaths(QStringList scriptPaths) { _scriptPaths = scriptPaths; }
@ -53,6 +54,7 @@ public:
signals:
void nameChanged(const QString& name);
void modelPathChanged(const QString& modelPath);
void marketplaceIDChanged();
private:
QString _fstPath;