mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Adds a new API to set this type, and an option to the Avatar App. * "eye" - Match the user eyes with the avatar eyes. The previous default behavior. If the avatar skull is larger then the user, it can cause the avatars body to lift off of the ground when the user looks down. * "head" - Match the user head with the avatar head. The new default behavior. This prevents the body from lifting off of the ground while wearing a large headed avatar. But can cause an offset between the users eyes and the avatars eyes.
841 lines
30 KiB
QML
841 lines
30 KiB
QML
import QtQuick 2.6
|
|
import QtQuick.Controls 2.2
|
|
import QtQuick.Layouts 1.3
|
|
import QtQml.Models 2.1
|
|
import QtGraphicalEffects 1.0
|
|
import controlsUit 1.0 as HifiControls
|
|
import stylesUit 1.0
|
|
import "avatarapp"
|
|
|
|
Rectangle {
|
|
id: root
|
|
width: 480
|
|
height: 706
|
|
|
|
property bool keyboardEnabled: true
|
|
property bool keyboardRaised: false
|
|
property bool punctuationMode: false
|
|
|
|
HifiControls.Keyboard {
|
|
id: keyboard
|
|
z: 1000
|
|
raised: parent.keyboardEnabled && parent.keyboardRaised && HMD.active
|
|
numeric: parent.punctuationMode
|
|
anchors {
|
|
left: parent.left
|
|
right: parent.right
|
|
bottom: parent.bottom
|
|
}
|
|
}
|
|
|
|
color: style.colors.white
|
|
property string getAvatarsMethod: 'getAvatars'
|
|
|
|
signal sendToScript(var message);
|
|
function emitSendToScript(message) {
|
|
sendToScript(message);
|
|
}
|
|
|
|
ListModel { // the only purpose of this model is to convert JS object to ListElement
|
|
id: currentAvatarModel
|
|
dynamicRoles: true;
|
|
function makeAvatarEntry(avatarObject) {
|
|
clear();
|
|
append(avatarObject);
|
|
return get(count - 1);
|
|
}
|
|
}
|
|
|
|
property var jointNames: []
|
|
property var currentAvatarSettings;
|
|
|
|
function fetchAvatarModelName(marketId, avatar) {
|
|
var xmlhttp = new XMLHttpRequest();
|
|
var url = "https://highfidelity.com/api/v1/marketplace/items/" + marketId;
|
|
xmlhttp.onreadystatechange = function() {
|
|
if (xmlhttp.readyState === XMLHttpRequest.DONE && xmlhttp.status === 200) {
|
|
try {
|
|
var marketResponse = JSON.parse(xmlhttp.responseText.trim())
|
|
|
|
if (marketResponse.status === 'success') {
|
|
avatar.modelName = marketResponse.data.title;
|
|
}
|
|
}
|
|
catch(err) {
|
|
//console.error(err);
|
|
}
|
|
}
|
|
}
|
|
xmlhttp.open("GET", url, true);
|
|
xmlhttp.send();
|
|
}
|
|
|
|
function getAvatarModelName() {
|
|
|
|
if (currentAvatar === null) {
|
|
return '';
|
|
}
|
|
if (currentAvatar.modelName !== undefined) {
|
|
return currentAvatar.modelName;
|
|
} else {
|
|
var marketId = allAvatars.extractMarketId(currentAvatar.avatarUrl);
|
|
if (marketId !== '') {
|
|
fetchAvatarModelName(marketId, currentAvatar);
|
|
}
|
|
}
|
|
|
|
var avatarUrl = currentAvatar.avatarUrl;
|
|
var splitted = avatarUrl.split('/');
|
|
|
|
return splitted[splitted.length - 1];
|
|
}
|
|
|
|
property string avatarName: currentAvatar ? currentAvatar.name : ''
|
|
property string avatarUrl: currentAvatar ? currentAvatar.thumbnailUrl : null
|
|
property bool isAvatarInFavorites: currentAvatar ? allAvatars.findAvatar(currentAvatar.name) !== undefined : false
|
|
property int avatarWearablesCount: currentAvatar ? currentAvatar.wearables.count : 0
|
|
property var currentAvatar: null;
|
|
function setCurrentAvatar(avatar, bookmarkName) {
|
|
var currentAvatarObject = allAvatars.makeAvatarObject(avatar, bookmarkName);
|
|
currentAvatar = currentAvatarModel.makeAvatarEntry(currentAvatarObject);
|
|
}
|
|
|
|
property url externalAvatarThumbnailUrl: '../../images/avatarapp/guy-in-circle.svg'
|
|
|
|
function fromScript(message) {
|
|
if (message.method === 'initialize') {
|
|
jointNames = message.data.jointNames;
|
|
emitSendToScript({'method' : getAvatarsMethod});
|
|
} else if (message.method === 'wearableUpdated') {
|
|
adjustWearables.refreshWearable(message.entityID, message.wearableIndex, message.properties, message.updateUI);
|
|
} else if (message.method === 'wearablesUpdated') {
|
|
var wearablesModel = currentAvatar.wearables;
|
|
wearablesModel.clear();
|
|
message.wearables.forEach(function(wearable) {
|
|
wearablesModel.append(wearable);
|
|
});
|
|
adjustWearables.refresh(currentAvatar);
|
|
} else if (message.method === 'scaleChanged') {
|
|
currentAvatar.avatarScale = message.value;
|
|
updateCurrentAvatarInBookmarks(currentAvatar);
|
|
} else if (message.method === 'externalAvatarApplied') {
|
|
currentAvatar.avatarUrl = message.avatarURL;
|
|
currentAvatar.thumbnailUrl = allAvatars.makeThumbnailUrl(message.avatarURL);
|
|
currentAvatar.entry.avatarUrl = currentAvatar.avatarUrl;
|
|
currentAvatar.modelName = undefined;
|
|
updateCurrentAvatarInBookmarks(currentAvatar);
|
|
} else if (message.method === 'settingChanged') {
|
|
currentAvatarSettings[message.name] = message.value;
|
|
} else if (message.method === 'changeSettings') {
|
|
currentAvatarSettings = message.settings;
|
|
} else if (message.method === 'bookmarkLoaded') {
|
|
setCurrentAvatar(message.data.currentAvatar, message.data.name);
|
|
var avatarIndex = allAvatars.findAvatarIndex(currentAvatar.name);
|
|
allAvatars.move(avatarIndex, 0, 1);
|
|
view.setPage(0);
|
|
} else if (message.method === 'bookmarkAdded') {
|
|
var avatar = allAvatars.findAvatar(message.bookmarkName);
|
|
if (avatar !== undefined) {
|
|
var avatarObject = allAvatars.makeAvatarObject(message.bookmark, message.bookmarkName);
|
|
for(var prop in avatarObject) {
|
|
avatar[prop] = avatarObject[prop];
|
|
}
|
|
if (currentAvatar.name === message.bookmarkName) {
|
|
currentAvatar = currentAvatarModel.makeAvatarEntry(avatarObject);
|
|
}
|
|
} else {
|
|
allAvatars.addAvatarEntry(message.bookmark, message.bookmarkName);
|
|
}
|
|
updateCurrentAvatarInBookmarks(currentAvatar);
|
|
} else if (message.method === 'bookmarkDeleted') {
|
|
pageOfAvatars.isUpdating = true;
|
|
|
|
var index = pageOfAvatars.findAvatarIndex(message.name);
|
|
var absoluteIndex = view.currentPage * view.itemsPerPage + index
|
|
|
|
allAvatars.remove(absoluteIndex)
|
|
pageOfAvatars.remove(index);
|
|
|
|
var itemsOnPage = pageOfAvatars.count;
|
|
var newItemIndex = view.currentPage * view.itemsPerPage + itemsOnPage;
|
|
|
|
if (newItemIndex <= (allAvatars.count - 1)) {
|
|
pageOfAvatars.append(allAvatars.get(newItemIndex));
|
|
} else {
|
|
if (!pageOfAvatars.hasGetAvatars()) {
|
|
pageOfAvatars.appendGetAvatars();
|
|
}
|
|
}
|
|
|
|
pageOfAvatars.isUpdating = false;
|
|
} else if (message.method === getAvatarsMethod) {
|
|
var getAvatarsData = message.data;
|
|
allAvatars.populate(getAvatarsData.bookmarks);
|
|
setCurrentAvatar(getAvatarsData.currentAvatar, '');
|
|
displayNameInput.text = getAvatarsData.displayName;
|
|
currentAvatarSettings = getAvatarsData.currentAvatarSettings;
|
|
|
|
var bookmarkAvatarIndex = allAvatars.findAvatarIndexByValue(currentAvatar);
|
|
if (bookmarkAvatarIndex === -1) {
|
|
currentAvatar.name = '';
|
|
} else {
|
|
currentAvatar.name = allAvatars.get(bookmarkAvatarIndex).name;
|
|
allAvatars.move(bookmarkAvatarIndex, 0, 1);
|
|
}
|
|
view.setPage(0);
|
|
} else if (message.method === 'updateAvatarInBookmarks') {
|
|
updateCurrentAvatarInBookmarks(currentAvatar);
|
|
} else if (message.method === 'selectAvatarEntity') {
|
|
adjustWearables.selectWearableByID(message.entityID);
|
|
}
|
|
}
|
|
|
|
function updateCurrentAvatarInBookmarks(avatar) {
|
|
var bookmarkAvatarIndex = allAvatars.findAvatarIndexByValue(avatar);
|
|
if (bookmarkAvatarIndex === -1) {
|
|
avatar.name = '';
|
|
view.setPage(0);
|
|
} else {
|
|
var bookmarkAvatar = allAvatars.get(bookmarkAvatarIndex);
|
|
avatar.name = bookmarkAvatar.name;
|
|
view.selectAvatar(bookmarkAvatar);
|
|
}
|
|
}
|
|
|
|
property bool isInManageState: false
|
|
|
|
Component.onDestruction: {
|
|
keyboard.raised = false;
|
|
}
|
|
|
|
AvatarAppStyle {
|
|
id: style
|
|
}
|
|
|
|
AvatarAppHeader {
|
|
id: header
|
|
z: 100
|
|
|
|
property string currentPage: "Avatar"
|
|
property bool mainPageVisible: !settings.visible && !adjustWearables.visible
|
|
|
|
Binding on currentPage {
|
|
when: settings.visible
|
|
value: "Avatar Settings"
|
|
}
|
|
Binding on currentPage {
|
|
when: adjustWearables.visible
|
|
value: "Adjust Wearables"
|
|
}
|
|
Binding on currentPage {
|
|
when: header.mainPageVisible
|
|
value: "Avatar"
|
|
}
|
|
|
|
pageTitle: currentPage
|
|
avatarIconVisible: mainPageVisible
|
|
settingsButtonVisible: mainPageVisible
|
|
onSettingsClicked: {
|
|
displayNameInput.focus = false;
|
|
root.keyboardRaised = false;
|
|
settings.open(currentAvatarSettings, currentAvatar.avatarScale);
|
|
}
|
|
}
|
|
|
|
Settings {
|
|
id: settings
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.top: header.bottom
|
|
anchors.bottom: parent.bottom
|
|
|
|
z: 3
|
|
|
|
onSaveClicked: function() {
|
|
var avatarSettings = {
|
|
dominantHand : settings.dominantHandIsLeft ? 'left' : 'right',
|
|
hmdAvatarAlignmentType : settings.hmdAvatarAlignmentTypeIsEyes ? 'eyes' : 'head',
|
|
collisionsEnabled : settings.environmentCollisionsOn,
|
|
otherAvatarsCollisionsEnabled : settings.otherAvatarsCollisionsOn,
|
|
animGraphOverrideUrl : settings.avatarAnimationOverrideJSON,
|
|
collisionSoundUrl : settings.avatarCollisionSoundUrl
|
|
};
|
|
|
|
emitSendToScript({'method' : 'saveSettings', 'settings' : avatarSettings, 'avatarScale': settings.scaleValue})
|
|
|
|
close();
|
|
}
|
|
onCancelClicked: function() {
|
|
emitSendToScript({'method' : 'revertScale', 'avatarScale' : avatarScaleBackup});
|
|
|
|
close();
|
|
}
|
|
|
|
onScaleChanged: {
|
|
emitSendToScript({'method' : 'setScale', 'avatarScale' : scale})
|
|
}
|
|
}
|
|
|
|
AdjustWearables {
|
|
id: adjustWearables
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.top: header.bottom
|
|
anchors.bottom: parent.bottom
|
|
jointNames: root.jointNames
|
|
onWearableUpdated: {
|
|
emitSendToScript({'method' : 'adjustWearable', 'entityID' : id, 'wearableIndex' : index, 'properties' : properties})
|
|
}
|
|
onWearableDeleted: {
|
|
emitSendToScript({'method' : 'deleteWearable', 'entityID' : id, 'avatarName' : avatarName});
|
|
}
|
|
onAdjustWearablesOpened: {
|
|
emitSendToScript({'method' : 'adjustWearablesOpened', 'avatarName' : avatarName});
|
|
}
|
|
onAdjustWearablesClosed: {
|
|
emitSendToScript({'method' : 'adjustWearablesClosed', 'save' : status, 'avatarName' : avatarName});
|
|
}
|
|
onWearableSelected: {
|
|
emitSendToScript({'method' : 'selectWearable', 'entityID' : id});
|
|
}
|
|
onAddWearable: {
|
|
emitSendToScript({'method' : 'addWearable', 'avatarName' : avatarName, 'url' : url});
|
|
}
|
|
|
|
z: 3
|
|
}
|
|
|
|
Rectangle {
|
|
id: mainBlock
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 30
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 30
|
|
anchors.top: header.bottom
|
|
anchors.bottom: favoritesBlock.top
|
|
|
|
// TextStyle1
|
|
RalewaySemiBold {
|
|
size: 24;
|
|
anchors.left: parent.left
|
|
anchors.top: parent.top
|
|
anchors.topMargin: 34
|
|
}
|
|
|
|
// TextStyle1
|
|
RalewaySemiBold {
|
|
id: displayNameLabel
|
|
size: 24;
|
|
anchors.left: parent.left
|
|
anchors.top: parent.top
|
|
anchors.topMargin: 25
|
|
text: 'Display Name'
|
|
}
|
|
|
|
InputField {
|
|
id: displayNameInput
|
|
|
|
font.family: "Fira Sans"
|
|
font.pixelSize: 15
|
|
anchors.left: displayNameLabel.right
|
|
anchors.leftMargin: 30
|
|
anchors.verticalCenter: displayNameLabel.verticalCenter
|
|
anchors.right: parent.right
|
|
width: 232
|
|
|
|
text: 'ThisIsDisplayName'
|
|
|
|
onEditingFinished: {
|
|
emitSendToScript({'method' : 'changeDisplayName', 'displayName' : text})
|
|
focus = false;
|
|
}
|
|
|
|
onFocusChanged: {
|
|
root.keyboardRaised = focus;
|
|
}
|
|
}
|
|
|
|
ShadowImage {
|
|
id: avatarImage
|
|
width: 134
|
|
height: 134
|
|
anchors.top: displayNameLabel.bottom
|
|
anchors.topMargin: 31
|
|
Binding on source {
|
|
when: avatarUrl !== ''
|
|
value: avatarUrl
|
|
}
|
|
|
|
visible: avatarImage.status !== Image.Loading && avatarImage.status !== Image.Error
|
|
fillMode: Image.PreserveAspectCrop
|
|
}
|
|
|
|
ShadowImage {
|
|
id: customAvatarImage
|
|
anchors.fill: avatarImage;
|
|
visible: avatarUrl === '' || avatarImage.status === Image.Error
|
|
source: externalAvatarThumbnailUrl
|
|
}
|
|
|
|
ShadowRectangle {
|
|
anchors.fill: avatarImage;
|
|
color: 'white'
|
|
visible: avatarImage.status === Image.Loading
|
|
radius: avatarImage.radius
|
|
|
|
dropShadowRadius: avatarImage.dropShadowRadius;
|
|
dropShadowHorizontalOffset: avatarImage.dropShadowHorizontalOffset
|
|
dropShadowVerticalOffset: avatarImage.dropShadowVerticalOffset
|
|
|
|
Spinner {
|
|
id: spinner
|
|
visible: parent.visible
|
|
anchors.fill: parent;
|
|
}
|
|
}
|
|
|
|
AvatarWearablesIndicator {
|
|
anchors.right: avatarImage.right
|
|
anchors.bottom: avatarImage.bottom
|
|
anchors.rightMargin: -radius
|
|
anchors.bottomMargin: 6.08
|
|
wearablesCount: avatarWearablesCount
|
|
visible: avatarWearablesCount !== 0
|
|
}
|
|
|
|
RowLayout {
|
|
id: star
|
|
anchors.top: avatarImage.top
|
|
anchors.topMargin: 11
|
|
anchors.left: avatarImage.right
|
|
anchors.leftMargin: 30.5
|
|
anchors.right: parent.right
|
|
|
|
spacing: 12.3
|
|
|
|
Image {
|
|
width: 21.2
|
|
height: 19.3
|
|
source: isAvatarInFavorites ? '../../images/FavoriteIconActive.svg' : '../../images/FavoriteIconInActive.svg'
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
}
|
|
|
|
// TextStyle5
|
|
FiraSansSemiBold {
|
|
size: 22;
|
|
Layout.fillWidth: true
|
|
text: isAvatarInFavorites ? avatarName : "Add to Favorites"
|
|
elide: Qt.ElideRight
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
enabled: !isAvatarInFavorites
|
|
anchors.fill: star
|
|
onClicked: {
|
|
createFavorite.onSaveClicked = function() {
|
|
var entry = currentAvatar.entry;
|
|
|
|
var wearables = [];
|
|
for(var i = 0; i < currentAvatar.wearables.count; ++i) {
|
|
wearables.push(currentAvatar.wearables.get(i));
|
|
}
|
|
|
|
entry.avatarEntites = wearables;
|
|
currentAvatar.name = createFavorite.favoriteNameText;
|
|
|
|
emitSendToScript({'method': 'addAvatar', 'name' : currentAvatar.name});
|
|
createFavorite.close();
|
|
}
|
|
|
|
var avatarThumbnail = (avatarUrl === '' || avatarImage.status === Image.Error) ?
|
|
externalAvatarThumbnailUrl : avatarUrl;
|
|
|
|
createFavorite.open(root.currentAvatar.wearables.count, avatarThumbnail);
|
|
}
|
|
}
|
|
|
|
// TextStyle3
|
|
RalewayRegular {
|
|
id: avatarNameLabel
|
|
size: 22;
|
|
text: getAvatarModelName();
|
|
elide: Qt.ElideRight
|
|
|
|
anchors.right: linkLabel.left
|
|
anchors.left: avatarImage.right
|
|
anchors.leftMargin: 30
|
|
anchors.top: star.bottom
|
|
anchors.topMargin: 11
|
|
property bool hasMarketId: currentAvatar && allAvatars.extractMarketId(currentAvatar.avatarUrl) !== '';
|
|
|
|
MouseArea {
|
|
enabled: avatarNameLabel.hasMarketId
|
|
anchors.fill: parent;
|
|
onClicked: emitSendToScript({'method' : 'navigate', 'url' : allAvatars.makeMarketItemUrl(currentAvatar.avatarUrl)})
|
|
}
|
|
color: hasMarketId ? style.colors.blueHighlight : 'black'
|
|
}
|
|
|
|
// TextStyle3
|
|
RalewayRegular {
|
|
id: wearablesLabel
|
|
size: 22;
|
|
anchors.left: avatarImage.right
|
|
anchors.leftMargin: 30
|
|
anchors.top: avatarNameLabel.bottom
|
|
anchors.topMargin: 16
|
|
color: 'black'
|
|
text: 'Wearables'
|
|
}
|
|
|
|
SquareLabel {
|
|
id: linkLabel
|
|
anchors.right: parent.right
|
|
anchors.verticalCenter: avatarNameLabel.verticalCenter
|
|
glyphText: "."
|
|
glyphSize: 22
|
|
onClicked: {
|
|
popup.showSpecifyAvatarUrl(currentAvatar.avatarUrl, function() {
|
|
var url = popup.inputText.text;
|
|
emitSendToScript({'method' : 'applyExternalAvatar', 'avatarURL' : url})
|
|
}, function(link) {
|
|
Qt.openUrlExternally(link);
|
|
});
|
|
}
|
|
}
|
|
|
|
SquareLabel {
|
|
anchors.right: parent.right
|
|
anchors.verticalCenter: wearablesLabel.verticalCenter
|
|
glyphText: "\ue02e"
|
|
|
|
onClicked: {
|
|
adjustWearables.open(currentAvatar);
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: favoritesBlock
|
|
height: 407
|
|
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.bottom: parent.bottom
|
|
|
|
color: style.colors.lightGrayBackground
|
|
|
|
// TextStyle1
|
|
RalewaySemiBold {
|
|
id: favoritesLabel
|
|
size: 24;
|
|
anchors.top: parent.top
|
|
anchors.topMargin: 15
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 30
|
|
text: "Favorites"
|
|
}
|
|
|
|
// TextStyle8
|
|
RalewaySemiBold {
|
|
id: manageLabel
|
|
color: style.colors.blueHighlight
|
|
size: 20;
|
|
anchors.top: parent.top
|
|
anchors.topMargin: 20
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 30
|
|
text: isInManageState ? "Back" : "Manage"
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onClicked: {
|
|
isInManageState = isInManageState ? false : true;
|
|
}
|
|
}
|
|
}
|
|
|
|
Item {
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 30
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 0
|
|
|
|
anchors.top: favoritesLabel.bottom
|
|
anchors.topMargin: 20
|
|
anchors.bottom: parent.bottom
|
|
|
|
GridView {
|
|
id: view
|
|
anchors.fill: parent
|
|
interactive: false;
|
|
currentIndex: currentAvatarIndexInBookmarksPage();
|
|
|
|
function currentAvatarIndexInBookmarksPage() {
|
|
return (currentAvatar && currentAvatar.name !== '' && !pageOfAvatars.isUpdating) ? pageOfAvatars.findAvatarIndex(currentAvatar.name) : -1;
|
|
}
|
|
|
|
property int horizontalSpacing: 18
|
|
property int verticalSpacing: 44
|
|
property int thumbnailWidth: 92
|
|
property int thumbnailHeight: 92
|
|
|
|
function selectAvatar(avatar) {
|
|
emitSendToScript({'method' : 'selectAvatar', 'name' : avatar.name})
|
|
}
|
|
|
|
function deleteAvatar(avatar) {
|
|
emitSendToScript({'method' : 'deleteAvatar', 'name' : avatar.name})
|
|
}
|
|
|
|
AvatarsModel {
|
|
id: allAvatars
|
|
}
|
|
|
|
property int itemsPerPage: 8
|
|
property int totalPages: Math.ceil((allAvatars.count + 1) / itemsPerPage)
|
|
property int currentPage: 0;
|
|
onCurrentPageChanged: {
|
|
currentIndex = Qt.binding(currentAvatarIndexInBookmarksPage);
|
|
}
|
|
|
|
property bool hasNext: currentPage < (totalPages - 1)
|
|
property bool hasPrev: currentPage > 0
|
|
|
|
function setPage(pageIndex) {
|
|
pageOfAvatars.isUpdating = true;
|
|
pageOfAvatars.clear();
|
|
var start = pageIndex * itemsPerPage;
|
|
var end = Math.min(start + itemsPerPage, allAvatars.count);
|
|
|
|
for(var itemIndex = 0; start < end; ++start, ++itemIndex) {
|
|
var avatarItem = allAvatars.get(start)
|
|
pageOfAvatars.append(avatarItem);
|
|
}
|
|
|
|
if (pageOfAvatars.count !== itemsPerPage) {
|
|
pageOfAvatars.appendGetAvatars();
|
|
}
|
|
|
|
currentPage = pageIndex;
|
|
pageOfAvatars.isUpdating = false;
|
|
}
|
|
|
|
model: AvatarsModel {
|
|
id: pageOfAvatars
|
|
|
|
property bool isUpdating: false;
|
|
property var getMoreAvatarsEntry: {'thumbnailUrl' : '', 'name' : '', 'getMoreAvatars' : true}
|
|
|
|
function appendGetAvatars() {
|
|
append(getMoreAvatarsEntry);
|
|
}
|
|
|
|
function hasGetAvatars() {
|
|
return count != 0 && get(count - 1).getMoreAvatars
|
|
}
|
|
|
|
function removeGetAvatars() {
|
|
if (hasGetAvatars()) {
|
|
remove(count - 1)
|
|
}
|
|
}
|
|
}
|
|
|
|
flow: GridView.FlowLeftToRight
|
|
|
|
cellHeight: thumbnailHeight + verticalSpacing
|
|
cellWidth: thumbnailWidth + horizontalSpacing
|
|
|
|
delegate: Item {
|
|
id: delegateRoot
|
|
height: GridView.view.cellHeight
|
|
width: GridView.view.cellWidth
|
|
|
|
Item {
|
|
id: container
|
|
width: 92
|
|
height: 92
|
|
|
|
Behavior on y {
|
|
NumberAnimation {
|
|
duration: 100
|
|
}
|
|
}
|
|
|
|
states: [
|
|
State {
|
|
name: "hovered"
|
|
when: favoriteAvatarMouseArea.containsMouse;
|
|
PropertyChanges { target: favoriteAvatarMouseArea; anchors.bottomMargin: -5 }
|
|
PropertyChanges { target: container; y: -5 }
|
|
PropertyChanges { target: favoriteAvatarImage; dropShadowRadius: 10 }
|
|
PropertyChanges { target: favoriteAvatarImage; dropShadowVerticalOffset: 6 }
|
|
},
|
|
State {
|
|
name: "getMoreAvatarsHovered"
|
|
when: getMoreAvatarsMouseArea.containsMouse;
|
|
PropertyChanges { target: getMoreAvatarsMouseArea; anchors.bottomMargin: -5 }
|
|
PropertyChanges { target: container; y: -5 }
|
|
PropertyChanges { target: getMoreAvatarsImage; dropShadowRadius: 10 }
|
|
PropertyChanges { target: getMoreAvatarsImage; dropShadowVerticalOffset: 6 }
|
|
}
|
|
]
|
|
|
|
property bool highlighted: delegateRoot.GridView.isCurrentItem
|
|
|
|
AvatarThumbnail {
|
|
id: favoriteAvatarImage
|
|
externalAvatarThumbnailUrl: root.externalAvatarThumbnailUrl
|
|
avatarUrl: thumbnailUrl
|
|
border.color: container.highlighted ? style.colors.blueHighlight : 'transparent'
|
|
border.width: container.highlighted ? 4 : 0
|
|
wearablesCount: {
|
|
return !getMoreAvatars ? wearables.count : 0
|
|
}
|
|
|
|
visible: !getMoreAvatars
|
|
|
|
MouseArea {
|
|
id: favoriteAvatarMouseArea
|
|
anchors.fill: parent
|
|
anchors.margins: 0
|
|
enabled: !container.highlighted
|
|
hoverEnabled: enabled
|
|
|
|
onClicked: {
|
|
if (isInManageState) {
|
|
var currentItem = delegateRoot.GridView.view.model.get(index);
|
|
popup.showDeleteFavorite(currentItem.name, function() {
|
|
view.deleteAvatar(currentItem);
|
|
});
|
|
} else {
|
|
if (delegateRoot.GridView.view.currentIndex !== index) {
|
|
var currentItem = delegateRoot.GridView.view.model.get(index);
|
|
popup.showLoadFavorite(currentItem.name, function() {
|
|
view.selectAvatar(currentItem);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.fill: favoriteAvatarImage
|
|
color: '#AFAFAF'
|
|
opacity: 0.4
|
|
radius: 5
|
|
visible: isInManageState && !container.highlighted && !getMoreAvatars
|
|
}
|
|
|
|
HiFiGlyphs {
|
|
anchors.fill: parent
|
|
text: "{"
|
|
visible: isInManageState && !container.highlighted && !getMoreAvatars
|
|
horizontalAlignment: Text.AlignHCenter
|
|
size: 56
|
|
}
|
|
|
|
ShadowRectangle {
|
|
id: getMoreAvatarsImage
|
|
width: 92
|
|
height: 92
|
|
radius: 5
|
|
color: style.colors.blueHighlight
|
|
visible: getMoreAvatars && !isInManageState
|
|
|
|
HiFiGlyphs {
|
|
anchors.centerIn: parent
|
|
|
|
color: 'white'
|
|
size: 60
|
|
text: "K"
|
|
}
|
|
|
|
MouseArea {
|
|
id: getMoreAvatarsMouseArea
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
|
|
onClicked: {
|
|
popup.showBuyAvatars(function() {
|
|
emitSendToScript({'method' : 'navigate', 'url' : 'hifi://BodyMart'})
|
|
}, function(link) {
|
|
emitSendToScript({'method' : 'navigate', 'url' : link})
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// TextStyle7
|
|
FiraSansRegular {
|
|
id: text
|
|
size: 18;
|
|
lineHeightMode: Text.FixedHeight
|
|
lineHeight: 16.9;
|
|
width: view.thumbnailWidth
|
|
height: view.verticalSpacing
|
|
elide: Qt.ElideRight
|
|
anchors.top: container.bottom
|
|
anchors.topMargin: 8
|
|
anchors.horizontalCenter: container.horizontalCenter
|
|
verticalAlignment: Text.AlignTop
|
|
horizontalAlignment: Text.AlignHCenter
|
|
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
|
text: getMoreAvatars ? 'Get More Avatars' : name
|
|
visible: !getMoreAvatars || !isInManageState
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
Row {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
|
|
Rectangle {
|
|
width: 40
|
|
height: 40
|
|
color: 'transparent'
|
|
|
|
PageIndicator {
|
|
x: 1
|
|
hasNext: view.hasNext
|
|
hasPrev: view.hasPrev
|
|
onClicked: view.setPage(view.currentPage - 1)
|
|
}
|
|
}
|
|
|
|
spacing: 0
|
|
|
|
Rectangle {
|
|
width: 40
|
|
height: 40
|
|
color: 'transparent'
|
|
|
|
PageIndicator {
|
|
x: -1
|
|
isPrevious: false
|
|
hasNext: view.hasNext
|
|
hasPrev: view.hasPrev
|
|
onClicked: view.setPage(view.currentPage + 1)
|
|
}
|
|
}
|
|
|
|
anchors.bottom: parent.bottom
|
|
anchors.bottomMargin: 20
|
|
}
|
|
}
|
|
|
|
MessageBoxes {
|
|
id: popup
|
|
}
|
|
|
|
CreateFavoriteDialog {
|
|
avatars: allAvatars
|
|
id: createFavorite
|
|
}
|
|
}
|