QmlMarketplace - bugfixes and Markup rendering of descriptions

* Render markup in descriptions (bold, italic, quote, etc.)
* Back button from marketplaces list now works properly
* Layout fixes
This commit is contained in:
Roxanne Skelly 2019-02-01 15:27:17 -08:00
parent 0fdbca8ade
commit 39ad36a4d0
4 changed files with 210 additions and 81 deletions

View file

@ -32,7 +32,7 @@ Rectangle {
property string activeView: "initialize" property string activeView: "initialize"
property int currentSortIndex: 0 property int currentSortIndex: 0
property string sortString: "" property string sortString: "recent"
property string categoryString: "" property string categoryString: ""
property string searchString: "" property string searchString: ""
property bool keyboardEnabled: HMD.active property bool keyboardEnabled: HMD.active
@ -45,6 +45,7 @@ Rectangle {
function getMarketplaceItems() { function getMarketplaceItems() {
marketplaceItemView.visible = false; marketplaceItemView.visible = false;
itemsList.visible = true; itemsList.visible = true;
licenseInfo.visible = false;
marketBrowseModel.getFirstPage(); marketBrowseModel.getFirstPage();
{ {
if(root.searchString !== undefined && root.searchString !== "") { if(root.searchString !== undefined && root.searchString !== "") {
@ -69,7 +70,6 @@ Rectangle {
target: GlobalServices target: GlobalServices
onMyUsernameChanged: { onMyUsernameChanged: {
console.log("LOGIN STATUS CHANGING");
Commerce.getLoginStatus(); Commerce.getLoginStatus();
} }
} }
@ -333,7 +333,7 @@ Rectangle {
break; break;
} }
} }
onTextChanged: root.searchString = text
onAccepted: { onAccepted: {
root.searchString = searchField.text; root.searchString = searchField.text;
getMarketplaceItems(); getMarketplaceItems();
@ -474,11 +474,11 @@ Rectangle {
anchors { anchors {
fill: parent fill: parent
topMargin: 120 topMargin: 115
bottomMargin: 50 bottomMargin: 50
} }
visible: true; visible: true
HifiModels.PSFListModel { HifiModels.PSFListModel {
id: marketBrowseModel id: marketBrowseModel
@ -565,17 +565,22 @@ Rectangle {
header: Item { header: Item {
id: itemsHeading id: itemsHeading
height: childrenRect.height height: childrenRect.height
width: parent.width width: parent.width
Rectangle {
id: itemsSpacer;
height: 20
}
Rectangle { Rectangle {
id: itemsLoginStatus; id: itemsLoginStatus;
anchors { anchors {
top: itemsSpacer.bottom
left: parent.left left: parent.left
right: parent.right right: parent.right
leftMargin: 15 leftMargin: 15
top: parent.top+15
} }
height: root.isLoggedIn ? 0 : 80 height: root.isLoggedIn ? 0 : 80
@ -598,7 +603,7 @@ Rectangle {
} }
width: 80; width: 80;
text: root.price ? root.price : "LOG IN" text: "LOG IN"
onClicked: { onClicked: {
sendToScript({method: 'needsLogIn_loginClicked'}); sendToScript({method: 'needsLogIn_loginClicked'});
@ -687,6 +692,7 @@ Rectangle {
} }
Item { Item {
id: sort id: sort
visible: searchString === undefined || searchString === ""
anchors { anchors {
top: searchScope.bottom; top: searchScope.bottom;
@ -695,7 +701,7 @@ Rectangle {
topMargin: 10; topMargin: 10;
leftMargin: 15; leftMargin: 15;
} }
height: childrenRect.height height: visible ? childrenRect.height : 0
RalewayRegular { RalewayRegular {
id: sortText id: sortText
@ -771,6 +777,7 @@ Rectangle {
focus: true focus: true
clip: true clip: true
highlightFollowsCurrentItem: false highlightFollowsCurrentItem: false
currentIndex: 1;
delegate: SortButton { delegate: SortButton {
width: 80 width: 80
@ -818,25 +825,39 @@ Rectangle {
id: marketplaceItemView id: marketplaceItemView
anchors.fill: parent anchors.fill: parent
anchors.topMargin: 120 anchors.topMargin: 115
anchors.bottomMargin: 50
width: parent.width width: parent.width
visible: false visible: false
ScrollView { ScrollView {
id: marketplaceItemScrollView id: marketplaceItemScrollView
anchors.fill: parent; anchors.fill: parent
clip: true clip: true
ScrollBar.vertical.policy: ScrollBar.AlwaysOn ScrollBar.vertical.policy: ScrollBar.AlwaysOn
contentWidth: parent.width contentWidth: parent.width
contentHeight: childrenRect.height
function resize() {
contentHeight = (marketplaceItemContent.y - itemSpacer.y + marketplaceItemContent.height);
}
Item {
id: itemSpacer
anchors.top: parent.top
height: 15
}
Rectangle { Rectangle {
id: itemLoginStatus; id: itemLoginStatus;
anchors { anchors {
left: parent.left left: parent.left
right: parent.right right: parent.right
top: itemSpacer.bottom
topMargin: 10
leftMargin: 15 leftMargin: 15
rightMargin: 15 rightMargin: 15
} }
@ -861,7 +882,7 @@ Rectangle {
} }
width: 80; width: 80;
text: root.price ? root.price : "LOG IN" text: "LOG IN"
onClicked: { onClicked: {
sendToScript({method: 'needsLogIn_loginClicked'}); sendToScript({method: 'needsLogIn_loginClicked'});
@ -890,9 +911,9 @@ Rectangle {
Rectangle { Rectangle {
id: marketplaceItemContent id: marketplaceItemContent
anchors.top: itemLoginStatus.bottom; anchors.top: itemLoginStatus.bottom
width: parent.width width: parent.width
height: childrenRect.height + 100 height: childrenRect.height;
RalewaySemiBold { RalewaySemiBold {
id: backText id: backText
@ -900,6 +921,7 @@ Rectangle {
anchors { anchors {
top: parent.top top: parent.top
left: parent.left left: parent.left
topMargin: 10
leftMargin: 15 leftMargin: 15
bottomMargin: 10 bottomMargin: 10
} }
@ -944,6 +966,10 @@ Rectangle {
categoriesText.text = category; categoriesText.text = category;
getMarketplaceItems(); getMarketplaceItems();
} }
onResized: {
marketplaceItemScrollView.resize();
}
} }
} }
} }
@ -975,37 +1001,64 @@ Rectangle {
leftMargin: 15 leftMargin: 15
} }
HiFiGlyphs { Item {
id: footerGlyph id: footerText
anchors.fill: parent
visible: itemsList.visible
HiFiGlyphs {
id: footerGlyph
anchors {
left: parent.left
top: parent.top
bottom: parent.bottom
rightMargin: 10
}
text: hifi.glyphs.info
size: 34
color: hifi.colors.white
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
RalewaySemiBold {
id: footerInfo
anchors {
left: footerGlyph.right
top: parent.top
bottom: parent.bottom
}
text: "Get items from Clara.io!"
color: hifi.colors.white
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
size: 18
}
}
HifiControlsUit.Button {
anchors { anchors {
left: parent.left left: parent.left
top: parent.top top: parent.top
bottom: parent.bottom bottom: parent.bottom
topMargin: 10
bottomMargin: 10
leftMargin: 10
rightMargin: 10 rightMargin: 10
} }
text: hifi.glyphs.info visible: marketplaceItemView.visible
size: 34 text: "< BACK"
color: hifi.colors.white width: 100
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
RalewaySemiBold { onClicked: {
id: footerInfo getMarketplaceItems();
anchors {
left: footerGlyph.right
top: parent.top
bottom: parent.bottom
} }
text: "Get items from Clara.io!"
color: hifi.colors.white
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
size: 18
} }
HifiControlsUit.Button { HifiControlsUit.Button {
@ -1023,7 +1076,7 @@ Rectangle {
width: 180 width: 180
onClicked: { onClicked: {
sendToScript({method: 'marketplace_marketplaces'}); sendToScript({method: 'marketplace_marketplaces', itemId: marketplaceItemView.visible ? marketplaceItem.item_id : undefined});
} }
} }
} }
@ -1041,7 +1094,7 @@ Rectangle {
anchors { anchors {
fill: root fill: root
topMargin: 100 topMargin: 120
bottomMargin: 0 bottomMargin: 0
} }
@ -1052,7 +1105,7 @@ Rectangle {
anchors { anchors {
bottomMargin: 1 bottomMargin: 1
topMargin: 50 topMargin: 60
leftMargin: 1 leftMargin: 1
rightMargin: 1 rightMargin: 1
fill: parent fill: parent

View file

@ -15,6 +15,7 @@ import Hifi 1.0 as Hifi
import QtQuick 2.9 import QtQuick 2.9
import QtQuick.Controls 2.2 import QtQuick.Controls 2.2
import QtGraphicalEffects 1.0 import QtGraphicalEffects 1.0
import QtWebEngine 1.5
import stylesUit 1.0 import stylesUit 1.0
import controlsUit 1.0 as HifiControlsUit import controlsUit 1.0 as HifiControlsUit
import "../../../controls" as HifiControls import "../../../controls" as HifiControls
@ -49,6 +50,11 @@ Rectangle {
categoriesListModel.append({"category":category}); categoriesListModel.append({"category":category});
}); });
} }
onDescriptionChanged: {
descriptionTextModel.clear();
descriptionTextModel.append({text: description})
}
signal buy() signal buy()
signal categoryClicked(string category) signal categoryClicked(string category)
@ -63,7 +69,7 @@ Rectangle {
onMarketplaceItemLikeResult: { onMarketplaceItemLikeResult: {
if (result.status !== 'success') { if (result.status !== 'success') {
console.log("Failed to get Marketplace Categories", result.data.message); console.log("Like/Unlike item", result.data.message);
} else { } else {
root.liked = !root.liked; root.liked = !root.liked;
root.likes = root.liked ? root.likes + 1 : root.likes - 1; root.likes = root.liked ? root.likes + 1 : root.likes - 1;
@ -98,24 +104,33 @@ Rectangle {
var sec = addLeadingZero(a.getSeconds()); var sec = addLeadingZero(a.getSeconds());
return a.toDateString() + " " + drawnHour + ':' + min + amOrPm; return a.toDateString() + " " + drawnHour + ':' + min + amOrPm;
} }
function evalHeight() {
height = footer.y - header.y + footer.height;
}
signal resized()
onHeightChanged: {
resized();
}
anchors { anchors {
left: parent.left; left: parent.left
right: parent.right; right: parent.right
leftMargin: 15; leftMargin: 15
rightMargin: 15; rightMargin: 15
} }
height: childrenRect.height; height: footer.y - header.y + footer.height
Rectangle { Rectangle {
id: header id: header
anchors { anchors {
left: parent.left; left: parent.left
right: parent.right; right: parent.right
top: parent.top; top: parent.top
} }
height: 50; height: 50
RalewaySemiBold { RalewaySemiBold {
id: nameText id: nameText
@ -137,10 +152,10 @@ Rectangle {
id: likes id: likes
anchors { anchors {
top: parent.top; top: parent.top
right: parent.right; right: parent.right
bottom: parent.bottom; bottom: parent.bottom
rightMargin: 5; rightMargin: 5
} }
RalewaySemiBold { RalewaySemiBold {
@ -216,7 +231,11 @@ Rectangle {
right: parent.right; right: parent.right;
top: itemImage.bottom; top: itemImage.bottom;
} }
height: childrenRect.height height: categoriesList.y - buyButton.y + categoriesList.height
function evalHeight() {
height = categoriesList.y - buyButton.y + categoriesList.height;
}
HifiControlsUit.Button { HifiControlsUit.Button {
id: buyButton id: buyButton
@ -309,7 +328,7 @@ Rectangle {
top: postedLabel.bottom top: postedLabel.bottom
left: parent.left left: parent.left
right: parent.right right: parent.right
topMargin: 10 topMargin: 5
} }
text: { getFormattedDate(root.created_at); } text: { getFormattedDate(root.created_at); }
@ -360,6 +379,7 @@ Rectangle {
anchors.top: licenseLabel.bottom anchors.top: licenseLabel.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.topMargin: 5
width: paintedWidth width: paintedWidth
text: root.license text: root.license
@ -371,9 +391,10 @@ Rectangle {
RalewaySemiBold { RalewaySemiBold {
id: licenseHelp id: licenseHelp
anchors.top: licenseText.bottom; anchors.top: licenseText.bottom
anchors.left: parent.left; anchors.left: parent.left
width: paintedWidth; anchors.topMargin: 5
width: paintedWidth
text: "More about this license" text: "More about this license"
size: 14 size: 14
@ -413,6 +434,7 @@ Rectangle {
Item { Item {
id: descriptionItem id: descriptionItem
property string text: ""
anchors { anchors {
top: licenseItem.bottom top: licenseItem.bottom
@ -421,13 +443,16 @@ Rectangle {
right: parent.right right: parent.right
} }
height: childrenRect.height height: childrenRect.height
onHeightChanged: {
footer.evalHeight();
}
RalewaySemiBold { RalewaySemiBold {
id: descriptionLabel id: descriptionLabel
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
width: paintedWidth width: paintedWidth
height: 20
text: "DESCRIPTION:" text: "DESCRIPTION:"
size: 14 size: 14
@ -435,18 +460,60 @@ Rectangle {
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
} }
RalewaySemiBold { //RalewaySemiBold {
id: descriptionText // id: descriptionText
//
// anchors.top: descriptionLabel.bottom
// anchors.left: parent.left
// anchors.topMargin: 5
// width: parent.width
//
// text: root.description
// size: 14
// color: hifi.colors.lightGray
// verticalAlignment: Text.AlignVCenter
// wrapMode: Text.Wrap
//}
ListModel {
id: descriptionTextModel
}
ListView {
id: descriptionTextView;
anchors.top: descriptionLabel.bottom anchors.top: descriptionLabel.bottom
anchors.left: parent.left anchors.left: parent.left
width: parent.width anchors.right: parent.right
text: root.description model: descriptionTextModel
size: 14 interactive: false
color: hifi.colors.lightGray
verticalAlignment: Text.AlignVCenter delegate: Component {
wrapMode: Text.Wrap Rectangle {
id: descriptionWebRect
width: parent.width
height: 5
WebEngineView {
id: descriptionWebView
anchors.fill: parent
Component.onCompleted: {
loadHtml("<html><head><style>body { color: #393939; font-family: Arial !important;}</style></head><body>"+model.text+"</body></html>");
}
onContentsSizeChanged: {
descriptionWebRect.height = contentsSize.height;
descriptionTextView.height = contentsSize.height;
}
onNewViewRequested: function(request) {
sendToScript({method: 'marketplace_open_link', link: request.requestedUrl});
}
}
}
}
} }
} }
@ -460,7 +527,7 @@ Rectangle {
right: parent.right right: parent.right
} }
width: parent.width width: parent.width
height: childrenRect.height height: childrenRect.height + 50
RalewaySemiBold { RalewaySemiBold {
id: categoryLabel id: categoryLabel
@ -480,12 +547,13 @@ Rectangle {
ListView { ListView {
anchors { anchors {
left: parent.left; left: parent.left
right: parent.right; right: parent.right
top: categoryLabel.bottom; top: categoryLabel.bottom
bottomMargin: 15
} }
height: 20*model.count height: 24*model.count+10
model: categoriesListModel model: categoriesListModel
delegate: RalewaySemiBold { delegate: RalewaySemiBold {
@ -496,7 +564,7 @@ Rectangle {
text: model.category text: model.category
size: 14 size: 14
height: 20 height: 24
color: hifi.colors.blueHighlight color: hifi.colors.blueHighlight
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter

View file

@ -76,9 +76,12 @@
if (document.referrer !== "") { if (document.referrer !== "") {
window.history.back(); window.history.back();
} else { } else {
EventBridge.emitWebEvent(JSON.stringify({ var params = { type: GOTO_MARKETPLACE };
type: GOTO_MARKETPLACE var itemIdMatch = location.search.match(/itemId=([^&]*)/);
})); if (itemIdMatch && itemIdMatch.length === 2) {
params.itemId = itemIdMatch[1];
}
EventBridge.emitWebEvent(JSON.stringify(params));
} }
}); });
$("#all-markets").on("click", function () { $("#all-markets").on("click", function () {

View file

@ -41,7 +41,6 @@ var GOTO_DIRECTORY = "GOTO_DIRECTORY";
var GOTO_MARKETPLACE = "GOTO_MARKETPLACE"; var GOTO_MARKETPLACE = "GOTO_MARKETPLACE";
var QUERY_CAN_WRITE_ASSETS = "QUERY_CAN_WRITE_ASSETS"; var QUERY_CAN_WRITE_ASSETS = "QUERY_CAN_WRITE_ASSETS";
var CAN_WRITE_ASSETS = "CAN_WRITE_ASSETS"; var CAN_WRITE_ASSETS = "CAN_WRITE_ASSETS";
var WARN_USER_NO_PERMISSIONS = "WARN_USER_NO_PERMISSIONS";
var CLARA_DOWNLOAD_TITLE = "Preparing Download"; var CLARA_DOWNLOAD_TITLE = "Preparing Download";
var messageBox = null; var messageBox = null;
@ -437,9 +436,8 @@ function rezEntity(itemHref, itemType, marketplaceItemTesterId) {
var referrerURL; // Used for updating Purchases QML var referrerURL; // Used for updating Purchases QML
var filterText; // Used for updating Purchases QML var filterText; // Used for updating Purchases QML
function onWebEventReceived(message) { function onWebEventReceived(message) {
message = JSON.parse(message);
if (message.type === GOTO_MARKETPLACE) { if (message.type === GOTO_MARKETPLACE) {
openMarketplace(); openMarketplace(message.itemId);
} else if (message.type === GOTO_DIRECTORY) { } else if (message.type === GOTO_DIRECTORY) {
// This is the chooser between marketplaces. Only OUR markteplace // This is the chooser between marketplaces. Only OUR markteplace
// requires/makes-use-of wallet, so doesn't go through openMarketplace bottleneck. // requires/makes-use-of wallet, so doesn't go through openMarketplace bottleneck.
@ -569,7 +567,14 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) {
case 'marketplace_marketplaces': case 'marketplace_marketplaces':
// This is the chooser between marketplaces. Only OUR markteplace // This is the chooser between marketplaces. Only OUR markteplace
// requires/makes-use-of wallet, so doesn't go through openMarketplace bottleneck. // requires/makes-use-of wallet, so doesn't go through openMarketplace bottleneck.
ui.open(MARKETPLACES_URL, MARKETPLACES_INJECT_SCRIPT_URL); var url = MARKETPLACES_URL;
if(message.itemId) {
url = url + "?itemId=" + message.itemId
}
ui.open(url, MARKETPLACES_INJECT_SCRIPT_URL);
break;
case 'marketplace_open_link':
ui.open(message.link);
break; break;
case 'checkout_rezClicked': case 'checkout_rezClicked':
case 'purchases_rezClicked': case 'purchases_rezClicked':