我们可以在Ubuntu的官方网站中得到关于Scope的更多的开发信息。在今天的这篇文章中,我们来主要介绍如何在Scope中截获在Preview中的按钮事件。在事件处理中,我们来做我们所需要的事情。在这篇文章中,我们将使用我们以前开发的weibo例子为例。在微博中,我们来发送一个我们需要的信息到微博中。最后我们的画面如下:
为了能够完成我们所需要的功能,我们首先下载我先前的代码: https://github.com/liu-xiao-guo/weibo。
我们首先在query.cpp中的run方法中加入如下的代码:
query.cpp
void Query::run(sc::SearchReplyProxy const& reply) {
// We will not show anything if the user does not login
if( !login(reply) )
return;
sc::CategoryRenderer rdr_new_blog(NEW_BLOG);
sc::Category::SCPtr cat_new_blog;
cat_new_blog = reply->lookup_category("new_blog");
if (!cat_new_blog)
cat_new_blog = reply->register_category("new_blog", "", "", rdr_new_blog);
sc::CategorisedResult res_new_blog(cat_new_blog);
res_new_blog.set_title(_("Create new blog post"));
res_new_blog.set_uri("http://weibo.com");
res_new_blog["getusertext"] = "key_existence_only_has_meaning_not_this_value";//whether to get text from user in preview
res_new_blog["newblog"] = "key_existence_only_has_meaning_not_this_value";//new blog, not reply
res_new_blog["noart"] = "key_existence_only_has_meaning_not_this_value";//whether preview has art
reply->push(res_new_blog);
....
}
这里,我们创建了一个类似按钮的叫做“Create new blog post”的显示:
同时,我们在“CategorisedResult”加入了一些我们可以区别其它的显示的项比如:
res_new_blog["getusertext"] = "key_existence_only_has_meaning_not_this_value";//whether to get text from user in preview
res_new_blog["newblog"] = "key_existence_only_has_meaning_not_this_value";//new blog, not reply
res_new_blog["noart"] = "key_existence_only_has_meaning_not_this_value";//whether preview has art
reply->push(res_new_blog);
这些项没有任何的实际的意义,只是在Preview中用来区分和其它的项有所不同。这样我们可以动态创建一些像,以使得对该项的处理和别的项不同。
preview.cpp
void Preview::run(sc::PreviewReplyProxy const& reply) {
// Support three different column layouts
sc::ColumnLayout layout1col(1), layout2col(2), layout3col(3);
// We define 3 different layouts, that will be used depending on the
// device. The shell (view) will decide which layout fits best.
// If, for instance, we are executing in a tablet probably the view will use
// 2 or more columns.
// Column layout definitions are optional.
// However, we recommend that scopes define layouts for the best visual appearance.
// Single column layout
layout1col.add_column( { "image", "header", "reviewId", "actions" });
// Two column layout
layout2col.add_column( { "image" });
layout2col.add_column( { "header", "reviewId", "actions" });
// Three cokumn layout
layout3col.add_column( { "image" });
layout3col.add_column( { "header", "reviewId", "actions" });
layout3col.add_column( { });
// Register the layouts we just created
reply->register_layout( { layout1col, layout2col, layout3col });
// Define the header section
sc::PreviewWidget w_header("header", "header");
// It has title and a subtitle properties
w_header.add_attribute_mapping("title", "title");
w_header.add_attribute_mapping("subtitle", "subtitle");
// Define the image section
sc::PreviewWidget w_image("image", "image");
// It has a single source property, mapped to the result's art property
w_image.add_attribute_mapping("source", "art");
Result result = PreviewQueryBase::result();
QString urlString(result["uri"].get_string().c_str());
// Create an Open button and provide the URI to open for this preview result
sc::PreviewWidget w_actions("actions", "actions");
sc::VariantBuilder builder;
builder.add_tuple({
{"id", Variant("open")},
{"label", Variant("Open")},
{"uri", sc::Variant(urlString.toStdString())} // uri set, this action will be handled by the Dash
});
w_actions.add_attribute_value("actions", builder.end());
PreviewWidgetList widgets({ w_header });
//used for blogging
PreviewWidget w_review("reviewId", "rating-input");
w_review.add_attribute_value("submit-label", Variant("Publish"));
w_review.add_attribute_value("visible", Variant("review"));
w_review.add_attribute_value("required", Variant("review"));
std::string reply_label = "Reply";
std::string max_chars_label = "140 characters max";
if (result.contains("newblog"))
w_review.add_attribute_value("review-label", Variant(max_chars_label));
if (result.contains("replyblog"))
w_review.add_attribute_value("review-label", Variant(reply_label + ": " + max_chars_label));
if (result.contains("getusertext"))
widgets.emplace_back(w_review);
if (!result.contains("noart"))
{
widgets.emplace_back(w_image);
widgets.emplace_back(w_actions);
}
// Push each of the sections
reply->push( widgets );
}
在Preview的run中,我们加入了reviewId,它在result中包含有“getusertext”才显示。当其它项不包含“noart”时,才显示image及action。
添加对action的支持
scope.cpp
sc::ActivationQueryBase::UPtr Scope::perform_action(us::Result const& result,
us::ActionMetadata const& metadata,
std::string const& widget_id,
std::string const& action_id)
{
return sc::ActivationQueryBase::UPtr(new Activation(result, metadata, widget_id, action_id, accessToken_));
}
activation.cpp
/*
* Copyright (C) 2015 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authored by: Kyle Nitzsche <kyle.nitzsche@canonical.com>
*
*/
#include <scope/activation.h>
#include <unity/UnityExceptions.h>
#include <QDebug>
#include <QCoreApplication>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
namespace us = unity::scopes;
Activation::Activation(us::Result const& result, us::ActionMetadata const& metadata, std::string const& widget_id, std::string const& action_id, std::string accessToken):
ActivationQueryBase(result, metadata),
action_id_(action_id),
accessToken_(accessToken)
{
}
Activation::~Activation()
{
}
void Activation::cancelled()
{
}
QString qstr_(std::string str)
{
return QString::fromStdString(str);
}
us::ActivationResponse Activation::activate()
{
qDebug() << "==== in activate(). action_id: "<< QString::fromStdString(action_id_);
bool dash_handles = false;
if (result().contains("dash_activation"))
dash_handles = true;
else if (action_id_ == "profile_url")
dash_handles = true;
if (dash_handles)
{
qDebug() << "==== dash_activation";
return us::ActivationResponse(us::ActivationResponse::Status::NotHandled);
}
QString uri;
QString accessToken = QString::fromStdString(accessToken_);
QString params_qs;
QString message = QString("%1").arg(qstr_(action_metadata().scope_data().get_dict()["review"].get_string()));
if (result().contains("newblog"))
{
qDebug() << "==== NEW BLOG";
uri = QString("https://api.weibo.com/2/statuses/update.json?access_token=%1").arg(accessToken);
params_qs = QString("status=%1").arg(message);
}
else if (result().contains("replyblog"))
{
qDebug() << "==== REPLY BLOG";
//qDebug() << "==== token: " << accessToken;
uri = QString("https://api.weibo.com/2/statuses/repost.json?access_token=%1").arg(accessToken);
QString id_ = QString("id=%1").arg(qstr_(result()["idstring"].get_string()));
QString msg_ = QString("status=%1").arg(message);
params_qs = QString("%1&%2").arg(msg_,id_);
//qDebug() << "==== params_qs: " << params_qs;
}
us::ActionMetadata am = action_metadata();
//TODO: ensure text is 140 chars or less or warn user somehow
qDebug() << "==== microblog url:\n" << uri;
QByteArray params;
params.append(params_qs);
QEventLoop loop;
QNetworkAccessManager manager;
QObject::connect(&manager, SIGNAL(finished(QNetworkReply*)), &loop, SLOT(quit()));
QObject::connect(&manager, &QNetworkAccessManager::finished, [](QNetworkReply *netReply) {
netReply->deleteLater();
QByteArray data_ba = netReply->readAll();
QJsonParseError err;
QJsonDocument doc = QJsonDocument::fromJson(data_ba, &err);
if (err.error != QJsonParseError::NoError) {
qCritical() << "Failed to parse server data: " << err.errorString();
}
});
QUrl url = QUrl(uri);
QNetworkRequest request(url);
QString mUserAgent = QString("%1 (Ubuntu)").arg("weibo-scope");
request.setRawHeader("User-Agent", mUserAgent.toStdString().c_str());
request.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded");
manager.post(request, params);
loop.exec();
return us::ActivationResponse(us::ActivationResponse::Status::ShowDash);
}
当任何一个按钮被按下后,“activate()”方法将被调用。我们可以通过截获这个事件来做任何我们想要做的事情。