Merge pull request #8454 from howard-stearns/ux-improvements

snapshot ux improvements
This commit is contained in:
David Kelly 2016-08-17 12:23:12 -08:00 committed by GitHub
commit 37dc324cec
13 changed files with 176 additions and 49 deletions

View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<g>
<path d="M25.9,20.6c0.29,0.15,0.47,0.38,0.48,0.72c0,0.7,0.1,2.92,0.08,3.62c1,0.3,3.61,1.19,4.56,1.45
c0.15,0.01,0.27,0.03,0.38,0.09c0.2,0.1,0.33,0.3,0.36,0.58c0.01,0.11,0.02,0.22,0.02,0.33c-0.03,1.5,0.01,1.08-0.05,2.58
c-0.06,1.55-0.78,2.72-2.21,3.34c-1.12,0.49-2.01,0.57-2.92,0.1c-0.25-0.13-0.5-0.3-0.76-0.51c-1.46-1.21-2.95-2.39-4.42-3.59
c-0.37-0.3-0.48-0.75-0.29-1.15c0.19-0.39,0.63-0.61,1.05-0.49c0.06,0.02,0.12,0.04,0.18,0.07c0.1,0.05,0.19,0.11,0.27,0.18
c0.64,0.51,1,1.02,1.63,1.53c0,0,0.01,0,0.01,0.01c0.01,0.01,0.04,0.01,0.09,0.04c0-0.12,0.01-0.23,0.01-0.33
c0.06-2.53,0.12-5.06,0.18-7.59c0.01-0.36,0.06-0.69,0.37-0.92c0.28-0.2,0.58-0.25,0.89-0.12C25.85,20.57,25.88,20.58,25.9,20.6
M26.64,19.16c-0.06-0.03-0.12-0.06-0.18-0.09c-0.83-0.36-1.74-0.25-2.48,0.3c-1,0.73-1.03,1.83-1.04,2.19
c-0.04,1.54-0.07,3.11-0.11,4.64c-0.07-0.02-0.13-0.05-0.2-0.07c-1.17-0.34-2.41,0.22-2.96,1.33c-0.26,0.53-0.32,1.14-0.18,1.71
c0.14,0.55,0.45,1.03,0.91,1.4c0.49,0.4,0.98,0.8,1.46,1.18c0.97,0.78,1.97,1.59,2.94,2.4c0.35,0.29,0.7,0.52,1.05,0.71
c1.72,0.88,3.28,0.39,4.3-0.06c1.96-0.86,3.09-2.55,3.18-4.76c0.03-0.89,0.04-1.13,0.04-1.47c0-0.23,0-0.51,0.01-1.13
c0-0.18,0-0.37-0.03-0.56c-0.1-0.82-0.54-1.49-1.23-1.84c-0.25-0.13-0.53-0.21-0.82-0.25c-0.56-0.16-1.57-0.49-2.48-0.79
c-0.27-0.09-0.53-0.17-0.78-0.25c-0.01-0.34-0.02-0.7-0.03-1.06C28.02,22.12,28,21.58,28,21.31
C27.99,20.39,27.49,19.59,26.64,19.16L26.64,19.16z"/>
</g>
<path d="M33.4,17.76l-2.87-2.64l-0.13,1.65c-1.42-0.61-3.13-0.95-4.95-0.95c-1.91,0-3.66,0.37-5.06,1.04l-0.23-1.76l-2.73,2.79
l3.35,2l-0.22-1.66c1.27-0.71,3.01-1.11,4.89-1.11c1.8,0,3.52,0.37,4.84,1.03l-0.14,1.79L33.4,17.76z"/>
<g>
<path class="st0" d="M25.64,19.86c0.29,0.15,0.47,0.38,0.48,0.72c0,0.7,0.1,2.92,0.08,3.62c1,0.3,3.61,1.19,4.56,1.45
c0.16,0.04,0.28,0.08,0.39,0.13c0.2,0.1,0.31,0.26,0.35,0.54c0.01,0.11,0.02,0.22,0.02,0.33c-0.03,1.5,0.01,1.08-0.05,2.58
c-0.06,1.55-0.78,2.72-2.21,3.34c-1.12,0.49-2.01,0.57-2.92,0.1c-0.25-0.13-0.5-0.3-0.76-0.51c-1.46-1.21-2.95-2.39-4.42-3.59
c-0.37-0.3-0.48-0.75-0.29-1.15c0.19-0.39,0.63-0.61,1.05-0.49c0.06,0.02,0.12,0.04,0.18,0.07c0.1,0.05,0.19,0.11,0.27,0.18
c0.64,0.51,1,1.02,1.63,1.53c0,0,0.01,0,0.01,0.01c0.01,0.01,0.04,0.01,0.09,0.04c0-0.12,0.01-0.23,0.01-0.33
c0.06-2.53,0.12-5.06,0.18-7.59c0.01-0.36,0.06-0.69,0.37-0.92c0.28-0.2,0.58-0.25,0.89-0.12C25.59,19.83,25.62,19.84,25.64,19.86
M26.38,18.42c-0.06-0.03-0.12-0.06-0.18-0.09c-0.83-0.36-1.74-0.25-2.48,0.3c-1,0.73-1.03,1.83-1.04,2.19
c-0.04,1.54-0.07,3.11-0.11,4.64c-0.07-0.02-0.13-0.05-0.2-0.07c-1.17-0.34-2.41,0.22-2.96,1.33c-0.26,0.53-0.32,1.14-0.18,1.71
c0.14,0.55,0.45,1.03,0.91,1.4c0.49,0.4,0.98,0.8,1.46,1.18c0.97,0.78,1.97,1.59,2.94,2.4c0.35,0.29,0.7,0.52,1.05,0.71
c1.72,0.88,3.28,0.39,4.3-0.06c1.96-0.86,3.09-2.55,3.18-4.76c0.03-0.89,0.04-1.13,0.04-1.47c0-0.23,0-0.51,0.01-1.13
c0-0.18,0-0.37-0.03-0.56c-0.1-0.82-0.45-1.41-1.13-1.76c-0.25-0.13-0.61-0.24-0.91-0.32c-0.56-0.16-1.57-0.49-2.48-0.79
c-0.27-0.09-0.53-0.17-0.78-0.25c-0.01-0.34-0.02-0.7-0.03-1.06c-0.02-0.57-0.03-1.11-0.04-1.38
C27.73,19.65,27.23,18.85,26.38,18.42L26.38,18.42z"/>
</g>
<path class="st0" d="M33.14,17.02l-2.87-2.64l-0.13,1.65c-1.42-0.61-3.13-0.95-4.95-0.95c-1.91,0-3.66,0.37-5.06,1.04l-0.23-1.76
l-2.73,2.79l3.35,2l-0.22-1.66c1.27-0.71,3.01-1.11,4.89-1.11c1.8,0,3.52,0.37,4.84,1.03l-0.14,1.79L33.14,17.02z"/>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

View file

@ -47,19 +47,19 @@ Window {
}
function goCard(card) {
if (useFeed) {
if (addressBarDialog.useFeed) {
storyCard.imageUrl = card.imageUrl;
storyCard.userName = card.userName;
storyCard.placeName = card.placeName;
storyCard.actionPhrase = card.actionPhrase;
storyCard.timePhrase = card.timePhrase;
storyCard.hifiUrl = card.hifiUrl;
storyCard.visible = true;
return;
}
addressLine.text = card.hifiUrl;
toggleOrGo(true);
}
property bool useFeed: false;
property var allPlaces: [];
property var allStories: [];
property int cardWidth: 200;
@ -73,12 +73,13 @@ Window {
// The buttons have their button state changed on hover, so we have to manually fix them up here
onBackEnabledChanged: backArrow.buttonState = addressBarDialog.backEnabled ? 1 : 0;
onForwardEnabledChanged: forwardArrow.buttonState = addressBarDialog.forwardEnabled ? 1 : 0;
onUseFeedChanged: { updateFeedState(); }
ListModel { id: suggestions }
ListView {
id: scroll
width: (3 * cardWidth) + (2 * hifi.layout.spacing);
width: backgroundImage.width;
height: cardHeight;
spacing: hifi.layout.spacing;
clip: true;
@ -106,9 +107,18 @@ Window {
}
highlightMoveDuration: -1;
highlightMoveVelocity: -1;
highlight: Rectangle { color: "transparent"; border.width: 2; border.color: "#1FA5E8"; z: 1; }
highlight: Rectangle { color: "transparent"; border.width: 4; border.color: "#1DB5ED"; z: 1; }
leftMargin: 50; // Start the first item over be about the same amount as the last item peeks through on the other side.
rightMargin: 50;
}
Image { // Just a visual indicator that the user can swipe the cards over to see more.
source: "../images/Swipe-Icon-single.svg"
width: 50;
anchors {
right: scroll.right;
verticalCenter: scroll.verticalCenter;
}
}
Image {
id: backgroundImage
source: "../images/address-bar.svg"
@ -181,9 +191,9 @@ Window {
id: placesButton
imageURL: "../images/places.svg"
buttonState: 1
defaultState: useFeed ? 0 : 1;
hoverState: useFeed ? 2 : -1;
onClicked: useFeed ? toggleFeed() : identity()
defaultState: addressBarDialog.useFeed ? 0 : 1;
hoverState: addressBarDialog.useFeed ? 2 : -1;
onClicked: addressBarDialog.useFeed ? toggleFeed() : identity()
anchors {
right: feedButton.left;
bottom: addressLine.bottom;
@ -193,9 +203,9 @@ Window {
id: feedButton;
imageURL: "../images/snap-feed.svg";
buttonState: 0
defaultState: useFeed ? 1 : 0;
hoverState: useFeed ? -1 : 2;
onClicked: useFeed ? identity() : toggleFeed();
defaultState: addressBarDialog.useFeed ? 1 : 0;
hoverState: addressBarDialog.useFeed ? -1 : 2;
onClicked: addressBarDialog.useFeed ? identity() : toggleFeed();
anchors {
right: parent.right;
bottom: addressLine.bottom;
@ -221,10 +231,13 @@ Window {
}
function toggleFeed () {
useFeed = !useFeed;
placesButton.buttonState = useFeed ? 0 : 1;
feedButton.buttonState = useFeed ? 1 : 0;
function toggleFeed() {
addressBarDialog.useFeed = !addressBarDialog.useFeed;
updateFeedState();
}
function updateFeedState() {
placesButton.buttonState = addressBarDialog.useFeed ? 0 : 1;
feedButton.buttonState = addressBarDialog.useFeed ? 1 : 0;
filterChoicesByText();
}
function getRequest(url, cb) { // cb(error, responseOfCorrectContentType) of url. General for 'get' text/html/json, but without redirects.
@ -361,7 +374,7 @@ Window {
}
function suggestable(place) {
if (useFeed) {
if (addressBarDialog.useFeed) {
return true;
}
return (place.place_name !== AddressManager.hostname) // Not our entry, but do show other entry points to current domain.
@ -396,7 +409,7 @@ Window {
// pageResults is now [ [ placeDataOneForDomainOne, placeDataTwoForDomainOne, ...], [ placeDataTwoForDomainTwo...] ]
pageResults.forEach(function (domainResults) {
allPlaces = allPlaces.concat(domainResults);
if (!addressLine.text && !useFeed) { // Don't add if the user is already filtering
if (!addressLine.text && !addressBarDialog.useFeed) { // Don't add if the user is already filtering
domainResults.forEach(function (place) {
if (suggestable(place)) {
suggestions.append(place);
@ -421,7 +434,7 @@ Window {
return makeModelData(story);
});
allStories = allStories.concat(stories);
if (!addressLine.text && useFeed) { // Don't add if the user is already filtering
if (!addressLine.text && addressBarDialog.useFeed) { // Don't add if the user is already filtering
stories.forEach(function (story) {
suggestions.append(story);
});
@ -435,7 +448,7 @@ Window {
function filterChoicesByText() {
suggestions.clear();
var words = addressLine.text.toUpperCase().split(/\s+/).filter(identity),
data = useFeed ? allStories : allPlaces;
data = addressBarDialog.useFeed ? allStories : allPlaces;
function matches(place) {
if (!words.length) {
return suggestable(place);

View file

@ -25,7 +25,7 @@ Rectangle {
property string actionPhrase: "did something";
property string timePhrase: "";
property string hifiUrl: storyCard.placeName;
property string imageUrl: Qt.resolvedUrl("../images/default-domain.gif");
property string imageUrl: Qt.resolvedUrl("../../images/default-domain.gif");
property var visitPlace: function (ignore) { };
color: "white";
HifiStyles.HifiConstants { id: otherHifi }

View file

@ -17,6 +17,8 @@
#include "Application.h"
#include "MainWindow.h"
#include <display-plugins/CompositorHelper.h>
#include <DependencyManager.h>
#include <OffscreenUi.h>
int DesktopScriptingInterface::getWidth() {
QSize size = qApp->getWindow()->windowHandle()->screen()->virtualSize();
@ -31,3 +33,11 @@ void DesktopScriptingInterface::setOverlayAlpha(float alpha) {
qApp->getApplicationCompositor().setAlpha(alpha);
}
void DesktopScriptingInterface::show(const QString& path, const QString& title) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "show", Qt::QueuedConnection, Q_ARG(QString, path), Q_ARG(QString, title));
return;
}
DependencyManager::get<OffscreenUi>()->show(path, title);
}

View file

@ -23,6 +23,7 @@ class DesktopScriptingInterface : public QObject, public Dependency {
public:
Q_INVOKABLE void setOverlayAlpha(float alpha);
Q_INVOKABLE void show(const QString& path, const QString& title);
int getWidth();
int getHeight();

View file

@ -26,3 +26,8 @@ void DialogsManagerScriptingInterface::toggleAddressBar() {
QMetaObject::invokeMethod(DependencyManager::get<DialogsManager>().data(),
"toggleAddressBar", Qt::QueuedConnection);
}
void DialogsManagerScriptingInterface::showFeed() {
QMetaObject::invokeMethod(DependencyManager::get<DialogsManager>().data(),
"showFeed", Qt::QueuedConnection);
}

View file

@ -18,6 +18,7 @@ class DialogsManagerScriptingInterface : public QObject {
Q_OBJECT
public:
DialogsManagerScriptingInterface();
Q_INVOKABLE void showFeed();
public slots:
void toggleAddressBar();

View file

@ -38,6 +38,7 @@ AddressBarDialog::AddressBarDialog(QQuickItem* parent) : OffscreenQmlDialog(pare
});
_backEnabled = !(DependencyManager::get<AddressManager>()->getBackStack().isEmpty());
_forwardEnabled = !(DependencyManager::get<AddressManager>()->getForwardStack().isEmpty());
connect(DependencyManager::get<DialogsManager>().data(), &DialogsManager::setUseFeed, this, &AddressBarDialog::setUseFeed);
}
void AddressBarDialog::loadAddress(const QString& address, bool fromSuggestions) {

View file

@ -20,15 +20,19 @@ class AddressBarDialog : public OffscreenQmlDialog {
HIFI_QML_DECL
Q_PROPERTY(bool backEnabled READ backEnabled NOTIFY backEnabledChanged)
Q_PROPERTY(bool forwardEnabled READ forwardEnabled NOTIFY forwardEnabledChanged)
Q_PROPERTY(bool useFeed READ useFeed WRITE setUseFeed NOTIFY useFeedChanged)
public:
AddressBarDialog(QQuickItem* parent = nullptr);
bool backEnabled() { return _backEnabled; }
bool forwardEnabled() { return _forwardEnabled; }
bool useFeed() { return _useFeed; }
void setUseFeed(bool useFeed) { if (_useFeed != useFeed) { _useFeed = useFeed; emit useFeedChanged(); } }
signals:
void backEnabledChanged();
void forwardEnabledChanged();
void useFeedChanged();
protected:
void displayAddressOfflineMessage();
@ -42,6 +46,7 @@ protected:
bool _backEnabled;
bool _forwardEnabled;
bool _useFeed { false };
};
#endif

View file

@ -54,6 +54,11 @@ void DialogsManager::showAddressBar() {
AddressBarDialog::show();
}
void DialogsManager::showFeed() {
AddressBarDialog::show();
emit setUseFeed(true);
}
void DialogsManager::toggleDiskCacheEditor() {
maybeCreateDialog(_diskCacheEditor);
_diskCacheEditor->toggle();

View file

@ -45,6 +45,7 @@ public:
public slots:
void toggleAddressBar();
void showAddressBar();
void showFeed();
void toggleDiskCacheEditor();
void toggleLoginDialog();
void showLoginDialog();
@ -63,6 +64,7 @@ public slots:
signals:
void addressBarToggled();
void addressBarShown(bool visible);
void setUseFeed(bool useFeed);
private slots:
void hmdToolsClosed();

View file

@ -21,6 +21,15 @@
max-width: 100%;
height:auto;
}
.prompt {
font-family: Raleway-SemiBold;
text-transform: none;
}
.sub-section-header > div > input {
margin-top:20px;
}
span.inline-checkbox { display:inline; }
@media (max-width: 768px){
.snapshot-column-left{
@ -37,6 +46,8 @@
.snapsection{
width:95% !important;
padding-right:0px;
margin-left: auto;
margin-right: auto;
}
div#sharing {
margin-top:50px;
@ -104,11 +115,14 @@
};
// beware of bug: Cannot send objects at top level. (Nested in arrays is fine.)
shareSelected = function() {
EventBridge.emitWebEvent(paths);
shareSelected = function () {
EventBridge.emitWebEvent(paths.concat({openFeed: document.getElementById("openFeed").checked}));
};
doNotShare = function() {
EventBridge.emitWebEvent([]);
doNotShare = function () {
EventBridge.emitWebEvent([{openFeed: document.getElementById("openFeed").checked}]);
};
snapshotSettings = function () {
EventBridge.emitWebEvent("openSettings");
};
</script>
@ -120,16 +134,23 @@
<div class="section-header snapsection">
<label>Snapshots sucessfully saved!</label>
</div>
<div id="sharing">
<div class="sub-section-header snapsection">
<label>Would you like to share?</label>
</div>
<div class="sub-section-header snapsection">
<input type="button" id="share" value="SHARE IN FEED" onclick="shareSelected()"/>
</div>
<div class="sub-section-header snapsection">
<input type="button" class="red" id="close" value="DON'T SHARE" onclick="doNotShare()"/>
<div class="sub-section-header snapsection">
<div id="sharing">
<div class="prompt">Would you like to share your pic in the Snapshots feed?</div>
<div>
<input type="button" class="blue" id="share" value="SHARE IN FEED" onclick="shareSelected()"/>
</div>
</div>
<div>
<input type="button" class="red" id="close" value="DON'T SHARE" onclick="doNotShare()"/>
</div>
</div>
<div class="sub-section-header snapsection">
<input type="button" value="Snapshot setttings" onclick="snapshotSettings()"/>
<span class="inline-checkbox property checkbox">
<input id="openFeed" type="checkbox" checked/>
<label for="openFeed">Open feed after</label>
</span>
</div>
</div>
<div id="snapshot-images" class="snapshot-column-right"/>

View file

@ -9,7 +9,7 @@
//
var SNAPSHOT_DELAY = 500; // 500ms
var toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
var resetOverlays;
var resetOverlays, recticleVisible;
var button = toolBar.addButton({
objectName: "snapshot",
imageURL: Script.resolvePath("assets/images/tools/snap.svg"),
@ -20,24 +20,39 @@ var button = toolBar.addButton({
alpha: 0.9,
});
function showFeedWindow() {
DialogsManager.showFeed();
}
var openFeed, outstanding;
function confirmShare(data) {
var dialog = new OverlayWebWindow('Snapshot', Script.resolvePath("html/ShareSnapshot.html"), 800, 470);
var dialog = new OverlayWebWindow('Snapshot Review', Script.resolvePath("html/ShareSnapshot.html"), 800, 470);
function onMessage(message) {
if (message == 'ready') { // The window can now receive data from us.
switch (message) {
case 'ready':
dialog.emitScriptEvent(data); // Send it.
return;
} // Rest is confirmation processing
dialog.webEventReceived.disconnect(onMessage); // I'm not certain that this is necessary. If it is, what do we do on normal close?
dialog.close();
dialog.deleteLater();
message = message.filter(function (picture) { return picture.share; });
if (message.length) {
print('sharing', message.map(function (picture) { return picture.localPath; }).join(', '));
message.forEach(function (data) {
Window.shareSnapshot(data.localPath);
openFeed = false;
outstanding = 0;
break;
case 'openSettings':
Desktop.show("hifi/dialogs/GeneralPreferencesDialog.qml", "GeneralPreferencesDialog");
break;
default:
dialog.webEventReceived.disconnect(onMessage); // I'm not certain that this is necessary. If it is, what do we do on normal close?
dialog.close();
dialog.deleteLater();
message.forEach(function (submessage) {
if (submessage.share) {
print('sharing', submessage.localPath);
outstanding++;
Window.shareSnapshot(submessage.localPath);
} else if (submessage.openFeed) {
openFeed = true;
}
});
} else {
print('declined to share', JSON.stringify(data));
if (openFeed && !outstanding) {
showFeedWindow();
}
}
}
dialog.webEventReceived.connect(onMessage);
@ -51,12 +66,17 @@ function snapshotShared(success) {
} else {
// for now just print an error.
print('snapshot upload/share failed');
}
}
if ((--outstanding <= 0) && openFeed) {
showFeedWindow();
}
}
function onClicked() {
// update button states
resetOverlays = Menu.isOptionChecked("Overlays");
reticleVisible = Reticle.visible;
Reticle.visible = false;
Window.snapshotTaken.connect(resetButtons);
button.writeProperty("buttonState", 0);
@ -84,6 +104,7 @@ function resetButtons(path, notify) {
}
// show hud
toolBar.writeProperty("visible", true);
Reticle.visible = reticleVisible;
// update button states
button.writeProperty("buttonState", 1);