细细品味Ubuntu Scope中的category renderer模版

当我第一次接触Ubuntu Scope时,我发现这个Category Renderer太神奇。它可以把我们想要的数据很简单而直接的方式呈现给我们。但是由于资料的限制,我们很难知道它最终的显示的形式是什么样的。我们可以在我们的英文的网站的文章“Customization
and branding
”找到一下信息。但是总觉得意犹未尽,加之没有代码,有时很难理解它到底讲的是什么。在这篇文章中,我们来详细地介绍各种模版,并看看它们的显示格式。详细这对广大的开发者来说非常有用。我们可以修改这些模版来显示我们所需要的内容。

    

创建一个最基本的Scope

我们可以利用我们的Ubuntu SDK来创建一个最基本的Scope应用。为了说明问题的方便,我们在这个Scope里,不准备从网路上抓取任何的数据。所有的数据都是从本地来。为了达到这个目的,我们在我们的scope.cpp中做了如下的修改:

scope.cpp

sc::SearchQueryBase::UPtr Scope::search(const sc::CannedQuery &query,
                                        const sc::SearchMetadata &metadata) {
    const QString scopePath = QString::fromStdString(scope_directory());
    // Boilerplate construction of Query
    return sc::SearchQueryBase::UPtr(new Query(query, metadata, scopePath, config_));
}

在这里,我们加入了scopePath,并把它传人到query类中。

query.cpp

Query::Query(const sc::CannedQuery &query, const sc::SearchMetadata &metadata,
     QString scopePath, Config::Ptr config) :
    sc::SearchQueryBase(query, metadata), scopePath_(scopePath), client_(config) {

    for ( int i = 0; i < 8; i ++ ) {
        QString name = QString("image").append(QString::number(i+1)).append(".jpg");
        QString image = QString("file://%1/images/%2").arg(scopePath).arg(name);
        images_ << image;
    }

    for ( int i = 0; i < 10; i ++ ) {
        QString name = QString("pic").append(QString::number(i+1)).append(".jpg");
        QString image = QString("file://%1/images/%2").arg(scopePath).arg(name);
        icons_ << image;
    }

    background_ = QString("file://%1/images/%2").arg(scopePath).arg("background.jpg");

}

在这里,我们得到scope的路径。我们在scope的安装目录中加入一个images的目录,并考入我们所需要的所有需要的文件:

[email protected]:~/scope/scopetemplates$ tree
.
├── cmake
│   ├── FindGMock.cmake
│   └── FindIntltool.cmake
├── CMakeLists.txt
├── CMakeLists.txt.user
├── data
│   ├── CMakeLists.txt
│   ├── icon.png
│   ├── images
│   │   ├── background.jpg
│   │   ├── image1.jpg
│   │   ├── image2.jpg
│   │   ├── image3.jpg
│   │   ├── image4.jpg
│   │   ├── image5.jpg
│   │   ├── image6.jpg
│   │   ├── image7.jpg
│   │   ├── image8.jpg
│   │   ├── pic10.jpg
│   │   ├── pic1.jpg
│   │   ├── pic2.jpg
│   │   ├── pic3.jpg
│   │   ├── pic4.jpg
│   │   ├── pic5.jpg
│   │   ├── pic6.jpg
│   │   ├── pic7.jpg
│   │   ├── pic8.jpg
│   │   └── pic9.jpg
│   ├── logo.png
│   ├── scopetemplates.liu-xiao-guo_scopetemplates.ini.in
│   └── screenshot.png
├── include
│   ├── api
│   │   ├── client.h
│   │   └── config.h
│   └── scope
│       ├── localization.h
│       ├── preview.h
│       ├── query.h
│       └── scope.h
├── manifest.json.in
├── po
│   ├── CMakeLists.txt
│   ├── Makefile.in.in
│   ├── POTFILES.in
│   └── scopetemplates.pot
├── readme.txt
├── scopetemplates.apparmor
├── setup.sh
├── src
│   ├── api
│   │   └── client.cpp
│   ├── CMakeLists.txt
│   └── scope
│       ├── preview.cpp
│       ├── query.cpp
│       └── scope.cpp
└── tests
    ├── CMakeLists.txt
    ├── server
    │   ├── forecast
    │   │   └── daily
    │   │       ├── London,uk.json
    │   │       ├── London,uk.xml
    │   │       ├── Manchester,uk.json
    │   │       └── Manchester,uk.xml
    │   ├── server.py
    │   └── weather
    │       ├── London,uk.json
    │       ├── London,uk.xml
    │       ├── Manchester,uk.json
    │       └── Manchester,uk.xml
    └── unit
        ├── CMakeLists.txt
        └── scope
            └── test-scope.cpp

为了能够push数据到我们所需要的界面,我们设计了如下的helper方法:

void Query::pushResult(sc::SearchReplyProxy const& reply,
                       const string renderer, int i) {
    stringstream ss;
    ss << i;
    string str = ss.str();

    auto cat = reply->register_category( "id" + str, "Template " + str ,
                                         "", sc::CategoryRenderer(renderer) );
    sc::CategorisedResult r(cat);
    r.set_uri( URI.toStdString() );
    r.set_art( images_[0].toStdString() );
    r["subtitle"] = "Subtitle " + str;
    r.set_title("Title " + str);
    r["summary"] = "Summary: " + str;
    r["fulldesc"] = "fulldesc: " + str;
    r["mascot"] = icons_[0].toStdString();
    r["emblem"] = icons_[1].toStdString();
    r["background"] = background_.toStdString();
    r["overlay-color"] = "#FF0000";

    QString likes = QString("%1 %2").arg(qstr(u8"\u261d "), "100");
    QString views = QString("%1 %2").arg(qstr(u8"   \u261f "), "99");
    std::string both = qstr("%1 %2").arg(likes,views).toStdString();
    sc::VariantBuilder builder;
    builder.add_tuple({
        {"value", Variant(both)}
    });
    builder.add_tuple({
        {"value", Variant("")}
    });
    r["attributes"] = builder.end();

    if (!reply->push(r))
        return;
}

void Query::pushResult(sc::SearchReplyProxy const& reply,
                       const std::shared_ptr<const Category> *cat, int i) {

    stringstream ss;
    ss << i;
    string str = ss.str();

    sc::CategorisedResult r(*cat);
    r.set_uri( URI.toStdString() );
    r.set_art( images_[i].toStdString() );
    r["subtitle"] = "Subtitle " + str;
    r.set_title("Title " + str);
    r["summary"] = "Summary: " + str;
    r["fulldesc"] = "fulldesc: " + str;
    r["mascot"] = icons_[0].toStdString();
    r["emblem"] = icons_[1].toStdString();

    QString likes = QString("%1 %2").arg(qstr(u8"\u261d "), "100");
    QString views = QString("%1 %2").arg(qstr(u8"   \u261f "), "99");
    std::string both = qstr("%1 %2").arg(likes,views).toStdString();
    sc::VariantBuilder builder;
    builder.add_tuple({
        {"value", Variant(both)}
    });
    builder.add_tuple({
        {"value", Variant("")}
    });
    r["attributes"] = builder.end();

    if (!reply->push(r))
        return;
}

这两个方法几乎加上了我们可以push的所有的项。如果大家需要有更多的了解,可以参阅“CategoryRenderer” API。

测试我们的CategoryRenderer模版

模版1

const static string CAT_RENDERER1
{
    R"(
    {
        "schema_version" : 1,
        "template" :
        {
            "category-layout" : "grid",
            "card-layout": "vertical",
            "card-size" : "large",
            "card-background": "#00FF00"
        },
        "components" :
        {
            "title" : "title",
            "art" : "art",
            "subtitle": "subtitle",
            "mascot": "mascot",
            "emblem": "emblem",
            "summary": "summary",
            "background": "background",
            "overlay-color": "overlay-color",
            "attributes": {
                "field": "attributes",
                "max-count": 2
            }
        }
    }
    )"
};

这个模版是一个非常全的模版,几乎涵盖了模版需要的所有的项。我们在可以通过如下的方式进行测试:

void Query::run(sc::SearchReplyProxy const& reply) {
    try {
        // The default is vertical
        pushResult(reply, CAT_RENDERER1, 1);

    } catch (domain_error &e) {
        // Handle exceptions being thrown by the client API
        cerr << e.what() << endl;
        reply->error(current_exception());
    }
}

显示的结果如下:

   

从这里可以看出来,这是一个vertical的显示,上面是一个图片,下面是一些文字。几乎所有的东西它都有了。同时它使用了一个在上面右图显示的背景图作为背景图片。如果把背景图拿掉,这样看的更清楚一些,并使用“medium”大小的图片,显示的效果如下:

const static string CAT_RENDERER1
{
    R"(
    {
        "schema_version" : 1,
        "template" :
        {
            "category-layout" : "grid",
            "card-layout": "vertical",
            "card-size" : "medium",
            "card-background": "#00FF00"
        },
        "components" :
        {
            "title" : "title",
            "art" : "art",
            "subtitle": "subtitle",
            "mascot": "mascot",
            "emblem": "emblem",
            "summary": "summary",
            "overlay-color": "overlay-color",
            "attributes": {
                "field": "attributes",
                "max-count": 2
            }
        }
    }
    )"
};

模版2

const static string CAT_RENDERER2
{
    R"(
    {
        "schema_version" : 1,
        "template" :
        {
            "category-layout" : "grid",
            "card-layout": "horizontal",
            "card-size" : "large",
            "card-background": "#00FF00"
        },
        "components" :
        {
            "title" : "title",
            "art" : "art",
            "subtitle": "subtitle",
            "mascot": "mascot",
            "emblem": "emblem",
            "summary": "summary",
            "background": "background",
            "overlay-color": "overlay-color",
            "attributes": {
                "field": "attributes",
                "max-count": 2
            }
        }
    }
    )"
};

可以看出来,这是一个horizontal的显示。

模版3

const static string CAT_RENDERER3 = R"(
{
   "schema-version": 1,
    "template": {
        "category-layout": "grid",
        "card-layout": "horizontal",
        "card-size": "medium",
        "card-background": "#00FF00"
    },
    "components": {
        "title": "title",
        "art" : {
            "field": "art"
        },
       "subtitle": "subtitle",
        "overlay-color": "overlay-color",
        "attributes": {
            "field": "attributes",
            "max-count": 2
        }
    }
}
)";

模版4

const static string CAT_RENDERER4
{
    R"(
    {
        "schema_version" : 1,
        "template" :
        {
            "category-layout" : "grid",
            "card-layout": "vertical",
            "card-size" : "medium"
        },
        "components" :
        {
            "title" : "title",
            "art" : "art",
            "subtitle": "subtitle",
            "overlay-color": "overlay-color",
            "attributes": {
                "field": "attributes",
                "max-count": 2
            }
        }
    }
    )"
};

模版5

const static string CAT_RENDERER5
{
    R"(
    {
        "schema_version" : 1,
        "template" :
        {
            "category-layout" : "grid",
            "card-layout": "vertical",
            "card-size" : "medium"
        },
        "components":
        {
          "title": "title",
          "subtitle": "subtitle",
          "overlay-color": "overlay-color",
          "art" : {
            "field": "art",
            "aspect-ratio": 2.0
          },
          "attributes": {
              "field": "attributes",
              "max-count": 2
          }
        }
    }
    )"
};

模版6

const static string CAT_RENDERER6
{
    R"(
    {
        "schema_version" : 1,
        "template" :
        {
            "category-layout" : "grid",
            "card-layout": "vertical",
            "card-size" : "medium"
        },
        "components":
        {
          "title": "title",
          "subtitle": "subtitle",
          "art" : {
            "field": "art",
            "aspect-ratio": 1.0
          },
          "overlay-color": "overlay-color",
          "attributes": {
              "field": "attributes",
              "max-count": 2
          }
        }
    }
    )"
};

模版7

const static string CAT_RENDERER7
{
    R"(
    {
        "schema_version" : 1,
        "template" :
        {
            "category-layout" : "grid",
            "card-layout": "vertical",
            "card-size" : "medium",
            "overlay": true

        },
        "components":
        {
          "title": "title",
          "subtitle": "subtitle",
          "art" : {
            "field": "art",
            "aspect-ratio": 1.0
          },
          "overlay-color": "overlay-color",
          "attributes": {
              "field": "attributes",
              "max-count": 2
          }
        }
    }
    )"
};

在这里,显示了一个overlay的效果。其实这个选项,可以加到任何一个其它的模版中去。这个练习让开发者自己去试吧。

模版8

const static string CAT_RENDERER8
{
    R"(
    {
        "schema_version" : 1,
        "template" :
        {
            "category-layout" : "grid",
            "card-layout": "vertical",
            "card-size" : "medium"
        },
        "components" :
        {
            "title" : "title",
            "art" : "art",
            "subtitle": "subtitle",
            "mascot": "mascot",
            "emblem": "emblem",
            "summary": "summary",
            "overlay-color": "overlay-color",
            "attributes": {
                "field": "attributes",
                "max-count": 2
            }
        }
    }
    )"
};

为了能对这个模版有多个显示,我特意添加了更多的数据显示,并使用如下的代码:

        auto cat = reply->register_category( "Grid", "Grid" ,
                                             "", sc::CategoryRenderer(CAT_RENDERER8) );

        for ( int i = 0; i < count/2; i ++ ) {
            pushResult( reply, &cat, i);
        }

模版9

const static string CAT_RENDERER9
{
    R"(
    {
        "schema_version" : 1,
        "template" :
        {
            "category-layout" : "carousel",
            "card-layout": "vertical",
            "card-size" : "medium"
        },
        "components" :
        {
            "title" : "title",
            "art" : "art",
            "subtitle": "subtitle",
            "mascot": "mascot",
            "emblem": "emblem",
            "summary": "summary",
            "overlay-color": "overlay-color",
            "attributes": {
                "field": "attributes",
                "max-count": 2
            }
        }
    }
    )"
};
        int count = images_.count();

        auto cat = reply->register_category( "Carousel", "Carousel" ,
                                         "", sc::CategoryRenderer(CAT_RENDERER9) );

        for ( int i = 0; i < count; i ++ ) {
            pushResult( reply, &cat, i);
        }

模版10

const std::string CAT_RENDERER10 = R"(
{
  "schema-version": 1,
  "template": {
    "category-layout": "grid",
    "card-size": "large",
    "overlay": true
  },
  "components": {
    "title": "title",
    "subtitle": "subtitle",
    "art" : {
      "field": "art",
      "aspect-ratio": 2.0
    }
  }
}

模版11

const std::string CAT_RENDERER11 = R"(
{
        "schema-version" : 1,
        "template" : {
            "category-layout" : "vertical-journal",
            "card-layout": "horizontal",
            "card-size": "small",
            "collapsed-rows": 0
        },
        "components" : {
            "title":"title",
            "subtitle":"subtitle",
            "summary":"summary",
            "art":{
                "field": "art",
                "aspect-ratio": 2
            }
        }
})";

模版12

const static string CAT_RENDERER12
{
    R"(
    {
        "schema_version" : 1,
        "template" :
        {
            "category-layout" : "vertical-journal",
            "card-layout": "vertical",
            "card-size" : "medium",
            "card-background": "#00FF00"
        },
        "components" :
        {
            "title" : "title",
            "art" : "art",
            "subtitle": "subtitle",
            "mascot": "mascot",
            "emblem": "emblem",
            "summary": "summary",
            "background": "background",
            "overlay-color": "overlay-color",
            "attributes": {
                "field": "attributes",
                "max-count": 2
            }
        }
    }
    )"
};

模版13

const static string CAT_RENDERER13
{
    R"(
    {
        "schema_version" : 1,
        "template" :
        {
            "category-layout" : "horizontal-list",
            "card-layout": "vertical",
            "card-size" : "large",
            "card-background": "#00FF00"
        },
        "components" :
        {
            "title" : "title",
            "art" : "art",
            "subtitle": "subtitle",
            "mascot": "mascot",
            "emblem": "emblem",
            "summary": "summary",
            "background": "background",
            "overlay-color": "overlay-color",
            "attributes": {
                "field": "attributes",
                "max-count": 2
            }
        }
    }
    )"
};
        auto cat = reply->register_category( "horizontal-list", "horizontal-list" ,
                                         "", sc::CategoryRenderer(CAT_RENDERER13) );

        for ( int i = 0; i < count; i ++ ) {
            pushResult( reply, &cat, i);
        }

整个项目的源码在: git clone https://gitcafe.com/ubuntu/scopetemplates.git

时间: 2024-10-12 17:30:38

细细品味Ubuntu Scope中的category renderer模版的相关文章

如何在Ubuntu Scope中定义设置变量并读取

在本遍文章中,我们来讲解怎么对我们的Ubuntu Scope进行设置.对Scope而言,有些时候我们希望能够使用设置来改变我们的显示,或对我们的搜索进行重新定义.关于更多Scope的开发,请参阅网站:http://developer.ubuntu.com/scopes/ 1)首先创建一个最基本的Scope 我们首先打开SDK,并选择"Unity Scope"模版.我们选择一个项目的名称为"settingscope": 接下来,我们选择"Empty scop

利用video PreviewWidget在Ubuntu Scope中播放video

在先前的例程中,我们探讨了如何利用audio PreviewWidget在Scope中播放音乐.在这篇文章中,我们将介绍如何使用videoPreviewWidget来播放一个video. 我们首先来下载我在上一篇文章中的例程: git clone https://gitcafe.com/ubuntu/scopetemplates_audio.git 为了加入video PreviewWidget,我在我们的例程中加入了如下的句子: query.cpp r["videoSource"]

怎么在Ubuntu Scope中获取location地址信息

Location信息对很多有地址进行搜索的应用来说非常重要.比如对dianping这样的应用来说,我们可以通过地址来获取当前位置的一些信息.在这篇文章中,我们来介绍如何获取Scope架构中的位置信息.这个位置信息可以对我们很多的搜索是非常重要的. 1)创建一个简单的Scope应用 我们首先打开SDK,并选择"Unity Scope"模版: 接下来,我们选择"Empty scope".这样我们就创建了我们的一个最基本的scope了. 我们可以运行我们的Scope.这是

如何在Ubuntu Scope中利用Filter来更加精准地提高搜索的质量

在Ubuntu的Scope,目前正在研发一个新的Filter的功能.我们可以在我们的开发者网站找到有关filter的更多的信息.在那里你可以看到一些关于filter的介绍,但是真正地入手去利用它还是有一定的难度的.今天在我们的例程中,我们来具体展示如何利用filter实现更好的搜索.在实际的应用中,比如我们可以通过filter来实现如下的ctrip的Scope:     在上面的中间的图中,我们可以看到"重庆"被选中了,在第二个列中,我们可以使用我们的department来进行从一个城

利用reviews PreviewWidget在Ubuntu Scope中显示评价等级

我们可以利用reviews PreviewWidget来对我们的结果进行显示评价.比如对点评来说,如果是5星的评价,我们可以显示5个星表示客户对商品最高认可. 参阅我们的API的连接,我们可以看到如下的代码: { PreviewWidget w1("summary", "reviews"); w1.add_attribute_value("rating-icon-empty", Variant("file:///tmp/star-emp

利用gallery在Ubuntu Scope中显示多张图片

在这篇文章中,我们将介绍如何使用gallery PreviewWidget在Scope Preview中显示多幅图片.更多关于PreviewWidget类型可以参阅API. 首先,我们来下载我们上一节课里讲到的scopetemplate例程: git clone https://gitcafe.com/ubuntu/scopetemplates_video.git 为了能够显示多幅图片,我们对我们的程序做了如下的修改: query.cpp // add an array to show the

在Ubuntu Scope的模版中利用attributes来显示额外的信息

我在昨天的文章中介绍了我设计的优酷Scope.在今天的练习中,我将对它的模版做一些小的改动,利用模版中的attributes项使得它的显示更加生动. 如果感兴趣的朋友,可以在如下的地址下载最新的youku scope: git clone https://gitcafe.com/ubuntu/youku_keywords.git 首先,我们在query.cpp中对它的模版做如下的改动: query.cpp const std::string NORMAL_TEMPLATE = R"( { &qu

利用audio PreviewWidget在Scope中来播放音乐

在我们的Scope PreviewWidget,我们可以利用audio PreviewWidget来播放我们的音乐.这对一些音乐的Scope来说,非常中要.在今天的练习中,我们来利用这个它来在我们的Scope中来试听我们的音乐. 首先我们来利用我们已经做好的Scope.我们可以下载我们先前做好的Scope: git clone https://gitcafe.com/ubuntu/scopetemplates.git 在我们的query.cpp中,我们来添加如下的项: query.cpp voi

使用golang来设计我们的Ubuntu Scope

我们知道golang越来越被很多的开发者来开发应用.go语言也可以用于开发Ubuntu Scope.在今天的教程中,我们将详细介绍如何使用go语言来开发我们的Scope.这对于很多的不太熟悉C/C++的开发者来说,无疑是一个福音.对我来说,这个语言也是比较新的.如果大家想学习golang的话,建议大家阅读"Go by Example". IDE选择 由于一些原因,目前我们的Ubuntu SDK并没有支持go语言的Scope的开发.可喜的是,我们可以使用Command Line来完成我们