Canonical Voices

Benjamin Zeller

or: here comes LXD

The next iteration of the Ubuntu SDK IDE

or: here comes LXD

After a long development process we are pleased to announce that the next version of the Ubuntu SDK IDE will go into beta testing phase as of today and it comes packed with a completely new builder and runtime backend to finally get rid of the biggest issues the SDK IDE has today.

Some people already heard rumours about new LXD based builders that should replace the schroot based ones. Well, the rumours are true and after some time of internal testing of our proof of concept version with just a few trusted testers we think it is time to show the new IDE to a bigger audience.

Now, before jumping right on the new packages let’s revisit some of the reasons why we had to move away from the schroot based builders:

The biggest issue is for sure the creation of new chroots right after installing the SDK. Bootstrapping a full Ubuntu root file system from live archives is very slow and error prone. Whenever there is a packaging issue in the archives or overlay PPA it is not possible to create new build targets. Which basically makes the SDK unusable until the packaging issues are fixes. LXD already has solved that problem, new containers are downloaded as compressed and ready-to-go image files, downloading is much faster and the resulting container will work for sure since it was tested by us before releasing it as opposed to the continuously changing Overlay PPA. Once an image has been downloaded it is cached, and spinning up a new container from the cache is a matter of seconds!

The second issue I want to highlight is our requirement to execute the applications locally on the desktop, but still supporting all Ubuntu versions that are currently officially supported. Which means we had to deal with a list of different Qt and UITK versions. We tried to solve that problem by providing a separate Qt+UITK package but it turned out we’d have to hack and rebuild so many packages to make that work that it was just not feasible. And this is not only a build time problem, but also a runtime problem. How should we continue to make it possible to run apps on the Desktop, using the hottest and newest components while maintaining LTS compatibility?

The answer was actually very simple: Use the containers as runtime targets and show the UI on the host’s X server.

There were a few more issues, like overall slowness and leaking mount points (everyone who ever had hundreds of mounts because of schroot, knows what I’m talking about), issues with ecryptfs and more.

Now, enough with the past, let’s look into the future and what has changed. It is good to know before starting that we have dropped support for the default Desktop Kit. Building and running on the Host is not supported by default anymore. The SDK IDE will not create other desktop run configurations than what automatically created by the qmake and cmake plugins. It is of course still possible to build and run on the host, but the run configuration needs to be created manually. Instead from now on it’s required to create a container that matches the host architecture where the application is executed in. It means that on the host system almost no additional packages are required as dependencies. 

All existing schroot based builders will not be used by the IDE anymore. The click chroots will remain on the host but will be decoupled from the Ubuntu SDK IDE.

Get started

Its simple, all that needs to be done is to add the SDK Release and the Tools Development PPA for the Ubuntu SDK tools:

sudo add-apt-repository ppa:ubuntu-sdk-team/tools-development

sudo apt update && sudo apt install ubuntu-sdk-ide

 

And we are done, the IDE is now be fully usable. It will discover the containers just as it used to do with the click chroots. From all aspects, the developer experience will not change much. Please keep in mind we are still beta testing so there will be most likely some bugs, either with the container images or with the IDE itself. Please report them to us either directly on IRC or via mailing list, or even better on the official ubuntu-sdk-ide project in launchpad:  https://bugs.launchpad.net/ubuntu-sdk-ide

Known issues and troubleshooting

The lxd group membership

Normally the LXD install process takes care of configuring the necessary group membership. But if it does not then we have to make sure the current user is part of the lxd group issue this command:

sudo useradd -G lxd `whoami`

After that please relogin to make the new group known to the login session.

Reset QtCreator settings

Sometimes the settings of QtCreator (the Qt application of the Ubuntu SDK IDE) break when switching back and forth between different version. When you see broken or ghost Kits, or possible misconfigured devices, or in general anything what is weird it is possible that pushing  the reset button on Qtcreator helps. Note, that it is a rather radical fix. It can be easily done with a single command:

$ rm ~/.config/QtProject/qtcreator ~/.config/QtProject/QtC*

Clean up old click chroots

As mentioned before the old schroots are detached from the SDK IDE, but they remain on the file system. With the following commands it is possible to clean up the click chroots:

$ sudo click chroot -a armhf -f ubuntu-sdk-15.04 destroy

$ sudo click chroot -a i386 -f ubuntu-sdk-15.04 destroy

These commands will free about 1.4GB disk space. The click chroots live under the /var/lib/schroot/chroots/ It is a good idea to check if that folder is empty and nothing is mounted there

$ mount|grep schroot

NVIDIA video driver

Deploying apps locally from the LXD container i snot possible on hosts using NVIDIA graphics driver. If the host has dual graphic processor then one workaround is to use the other one.

Check if you have a backup graphics card

$ sudo lshw -class display

If that list shows other entries than the NVIDIA the activate the other video card. The prime select tool is a simple and easy tool to use.

$ sudo prime-select intel

Note that this tool might not be installed on your system and it does not work together with bumblebee. In case the host has bumblebee installed and missing the prime-select tool

$ sudo apt-get remove bumblebee

$ sudo apt-get install nvidia-prime

If the host has no other video card then the NVIDIA it is possible to use the Nouveau driver what might work. Anywhow, this is a known and very sever issue what we are working on.

Let start the new IDE

But first back up  some settings for the very unlikely case that we want to move back to the present IDE

$ tar zcvf ~/Qtproject.tar.gz ~/.config/QtProject

Then find the Ubuntu SDK IDE in the Dash and start it

The first thing the Ubuntu SDK IDE will do is checking if the environment is properly set up. Unless you are an LXC/LXD power user it is safe to choose 'Yes' in this dialog.

If the Ubuntu SDK is started for the first time, it will open a welcome wizard to help with setting up kits and devices

The best advice after this point is to read each page of the wizard and follow the instructions. It is a fairly easy process.
On the next page the wizard will offer you help to create kits

Push the "Create new Kit" button and read the target creation dialog

At this step we can choose between 3 types of targets:

  • "Build to run on the desktop", will filter for all images compatible with the desktop
  • "Build to run on device or emulator", will filter for all images that can be used for devices
  • "Show all available images", will show all available images

Let's select "Show all available images" to get an overview of all existing images.

As next we choose the preferred target arch. The Ubuntu phones and tablets are armhf and the host PC is either i386 or amd64. So for creating click packages for the phone we will need an armhf target and testing the application on the desktop we will need a native amd64 or i386 target

We can use the default naming for the kits.

Creating an LXD container requires system administrator rights, so at this point we need to authenticate ourself

Once we have entered the right password the download of the LXD image will start

It will take some time, depending on our network bandwidth. Each image is about 400MB. While the wizard downloads and configures the LXD image we have just enough time to read a quick blog post about what the Kits actually are: Everything You Always Wanted to Know About Kits But Were Afraid to Ask . It is not an exaggeration to say that the best way to invest the time is to read that blogpost and understand what the development kits are.

Once the container creation is done a simple dialog will show us some basic details

The next page of the wizard will help to set up target devices. In our case we already had a bq (krillin) phone and an emulator from the rc-proposed channel.


But even if there is no phone, tablet or emulator device available it is safe to finish the wizard.
At this stage the IDE will automatically discover the LXD container and offer us to update it.

It is not a mandatory step and perfectly safe to cancel that dialog.

After finishing the wizard the IDE will open up

 

 

Read more
David Callé

A new version of Snapcraft, the tool to create snaps to distribute your software, was recently released: Snapcraft 2.10 is packed with new features and improvements, including:

  • The ‘snapcraft init’ command now produces a template to bootstrap developers to create their snaps and uses ‘devmode’ as the default confinement mode
  • Added support for zip files, which can now be used as a source to be snapped for most Snapcraft plugins.
  • Renamed the ‘strip’ step to ‘prime’. Use of ‘strip’, the former snap lifecycle step, will print deprecation warnings
  • Initial backend support to work on the parts ecosystem
  • Migration to macaroons for authentication. The decentralized, cloud-aware authentication system will enable the addition of more features to talk to the Ubuntu Store APIs and a better developer experience. After this change, developers will need to do a one-off relogin to do uploads
  • A new ‘assumes’ field, which will be used by snapd to assert certain features are supported by the system for a particular snap to work properly
  • General polish around command output and error messages
  • Improvements to the Go and nodejs plugins

Check out the full details on all bug fixes and new features in Snapcraft 2.10.

Install Snapcraft

On Ubuntu

Simply open up a terminal with Ctrl+Alt+t and run these commands to install Snapcraft from the Ubuntu archives on Ubuntu 16.04 LTS

sudo apt update
sudo apt install snapcraft

On other platforms

Get the Snapcraft source code ›

Craft your snaps!

There is a thriving community of developers who can give you a hand getting started or unblocking you when creating your snap. You can participate and get help in multiple ways:

Last but not least the Snapcraft team would like to thank all the contributions from our community, keep them coming!

What’s next?

Next release, 2.11, will include improved documentation and getting started utilities. Subsequent releases will focus on the parts ecosystem, plugins, pull sources, and better integration with the Ubuntu Store for registration, uploads and snap releases.

Read more
Daniel Holbach

In Snappy Playpen we want to bring people together who want to create snaps, document best practices, learn from each other and have fun.

In our first Snappy Playpen event last Tuesday we simply wanted to bring people together, invite them to get to know the team, get started together and see how things go. It went great, check out the report!

Next week, on Tuesday, 14th June, we want to meet up and snap software together again. Obviously you can join #snappy on Freenode or the playpen gitter channel (or contribute to Snappy Playpen) at any time, but on Tuesday we want to get everyone together and make another push to get good stuff landed together.

This time we want to especially extend the invitation to all upstreams who are interested in getting their software snapped. If you are interested and need help, join us and we will figure out things together. If you still need to be convinced, here are a few reasons why this might make sense for your project:

  • Just run snapcraft upload to upload a snap to the store. (Maybe even hook it up with your CI?)
  • No lengthy review process. Publication within seconds.
  • Use different channels (stable, beta, edge) to ship different versions of your software to different audiences.
  • Build instructions in snapcraft.yaml are very simple, all nice and declarative.
  • Millions of Ubuntu 16.04 users can easily install your software through the software center.

We would also like to invite all Ubuntu flavours to participate. If you want to play around with snaps, we will help you get started.

  • WHAT: Snappy playpen sprint
  • WHEN: Tuesday, 14th June 2016 all day
  • WHERE: Join us on gitter or IRC

Read more
pitti

Historically, the “adt-run” command line has allowed multiple tests; as a consequence, arguments like --binary or --override-control were position dependent, which confused users a lot (#795274, #785068, #795274, LP #1453509). On the other hand I don’t know anyone or any CI system which actually makes use of the “multiple tests on a single command line” feature.

The command line also was a bit confusing in other ways, like the explicit --built-tree vs. --unbuilt-tree and the magic / vs. // suffixes, or option vs. positional arguments to specify tests.

The other long-standing confusion is the pervasive “adt” acronym, which is still from the very early times when “autopkgtest” was called “autodebtest” (this was changed one month after autodebtest’s inception, in 2006!).

Thus in some recent night/weekend hack sessions I’ve worked on a new command line interface and consistent naming. This is now available in autopkgtest 4.0 in Debian unstable and Ubuntu Yakkety. You can download and use the deb package on Debian jessie and Ubuntu ≥ 14.04 LTS as well. (I will provide official backports after the first bug fix release after this got some field testing.)

New “autopkgtest” command

The adt-run program is now superseded by autopkgtest:

  • It accepts only exactly one tested source package, and gives a proper error if none or more than one (often unintend) is given. Binaries to be tested, --override-control, etc. can now be specified in any order, making the arguments position independent. So you now can do things like:
    autopkgtest *.dsc *.deb [...]

    Before, *.deb only applied to the following test.

  • The explicit --source, --click-source etc. options are gone, the type of tested source/binary packages, including built vs. unbuilt tree, is detected automatically. Tests are now only specified with positional arguments, without the need (or possibility) to explicitly specify their type. The one exception is --installed-click com.example.myapp as possible names are the same as for apt source package names.
    # Old:
    adt-run --unbuilt-tree pkgs/foo-2 [...]
    # or equivalently:
    adt-run pkgs/foo-2// [...]
    
    # New:
    autopkgtest pkgs/foo-2
    # Old:
    adt-run --git-source http://example.com/foo.git [...]
    # New:
    autopkgtest http://example.com/foo.git [...]
    
  • The virtualization server is now separated with a double instead of a tripe dash, as the former is standard Unix syntax.
  • It defaults to the current directory if that is a Debian source package. This makes the command line particularly simple for the common case of wanting to run tests in the package you are just changing:
    autopkgtest -- schroot sid

    Assuming the current directory is an unbuilt Debian package, this will build the package, and run the tests in ./debian/tests against the built binaries.

  • The virtualization server must be specified with its “short” name only, e. g. “ssh” instead of “adt-virt-ssh”. They also don’t get installed into $PATH any more, as it’s hardly useful to call them directly.

README.running-tests got updated to the new CLI, as usual you can also read the HTML online.

The old adt-run CLI is still available with unchanged behaviour, so it is safe to upgrade existing CI systems to that version.

Image build tools

All adt-build* tools got renamed to autopkgtest-build*, and got changed to build images prefixed with “autopkgtest” instead of “adt”. For example, adt-build-lxc ubuntu xenial now produces an autopkgtest-xenial container instead of adt-xenial.

In order to not break existing CI systems, the new autopkgtest package contains symlinks to the old adt-build* commands, and when being called through them, also produce images with the old “adt-” prefix.

Environment variables in tests

Finally there is a set of environment variables that are exported by autopkgtest for using in tests and image customization tools, which now got renamed from ADT_* to AUTOPKGTEST_*:

  • AUTOPKGTEST_APT_PROXY
  • AUTOPKGTEST_ARTIFACTS
  • AUTOPKGTEST_AUTOPILOT_MODULE
  • AUTOPKGTEST_NORMAL_USER
  • AUTOPKGTEST_REBOOT_MARK
  • AUTOPKGTEST_TMP

As these are being used in existing tests and tools, autopkgtest also exports/checks those under their old ADT_* name. So tests can be converted gradually over time (this might take several years).

Feedback

As usual, if you find a bug or have a suggestion how to improve the CLI, please file a bug in Debian or in Launchpad. The new CLI is recent enough that we still have some liberty to change it.

Happy testing!

Read more
David Callé

We announced the Snappy Playpen a few days ago and yesterday was the Kickoff event where we basically invited everyone who was interested, brought in a lot of snapd and snapcraft experts and started snapping software together.

It was simply beautiful to see the level of excitement, the collaboration, how people got to know each other and how much stuff got done. Big hugs to everyone involved - great work!

People

Along with the usual #snappy IRC channel on Freenode, we used gitter.im as an experiment and it worked out well. We had at least 40 people participating there (many more on IRC and the mailing list), 850 messages in gitter alone and even after 24 hours we're still working our way through some software to go into the Playpen repository.

Without further ado, here's what already landed in the Snappy Playpen since yesterday:

Landed in the playpen:

Another beautiful thing which landed is Vincent Jobard's French video tutorial about Snapcraft just in time to celebrate the kickoff.

We have many great things which are still work in progress:

Not targeting the Snappy Playpen, but still nice snaps we worked on together as a team:

We also used this time to improve our crowdsourced docs on AskUbuntu:

The Snapcraft mailing-list has been buzzing with questions, answers and discussions:

And of course, kudos to the experts who managed to be very active and helpful, while preparing new releases of snapd and snapcraft.

Until the next Playpen event, which will be more focused on a specific software/framework/technology, we encourage you to have a look at all the snaps and snapcraft recipes available in the repo. Git clone it, cd into a project and run snapcraft to see how all the pieces are coming together to create a snap.

If you are the upstream of one of the above apps, help yourself with these branches and get in touch with us on IRC (freenode/#snappy), Gitter or on the mailing-list so we can provide support if needed.

Read more
Stéphane Graber

This is the tenth blog post in this series about LXD 2.0.

LXD logo

Introduction

Juju is Canonical’s service modeling and deployment tool. It supports a very wide range of cloud providers to make it easy for you to deploy any service you want on any cloud you want.

On top of that, Juju 2.0 also includes support for LXD, both for local deployments, ideal for development and as a way to co-locate services on a cloud instance or physical machine.

This post will focus on the local use case, going through the experience of a LXD user without any pre-existing Juju experience.

 

Requirements

This post assumes that you already have LXD 2.0 installed and configured (see previous posts) and that you’re running it on Ubuntu 16.04 LTS.

Setting up Juju

The first thing to do is to install Juju 2.0. On Ubuntu 16.04, it’s as simple as:

stgraber@dakara:~$ sudo apt install juju
Reading package lists... Done
Building dependency tree 
Reading state information... Done
The following additional packages will be installed:
 juju-2.0
Suggested packages:
 juju-core
The following NEW packages will be installed:
 juju juju-2.0
0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
Need to get 39.7 MB of archives.
After this operation, 269 MB of additional disk space will be used.
Do you want to continue? [Y/n] 
Get:1 http://us.archive.ubuntu.com/ubuntu xenial-updates/main amd64 juju-2.0 amd64 2.0~beta7-0ubuntu1.16.04.1 [39.6 MB]
Get:2 http://us.archive.ubuntu.com/ubuntu xenial-updates/main amd64 juju all 2.0~beta7-0ubuntu1.16.04.1 [9,556 B]
Fetched 39.7 MB in 0s (53.4 MB/s)
Selecting previously unselected package juju-2.0.
(Reading database ... 255132 files and directories currently installed.)
Preparing to unpack .../juju-2.0_2.0~beta7-0ubuntu1.16.04.1_amd64.deb ...
Unpacking juju-2.0 (2.0~beta7-0ubuntu1.16.04.1) ...
Selecting previously unselected package juju.
Preparing to unpack .../juju_2.0~beta7-0ubuntu1.16.04.1_all.deb ...
Unpacking juju (2.0~beta7-0ubuntu1.16.04.1) ...
Processing triggers for man-db (2.7.5-1) ...
Setting up juju-2.0 (2.0~beta7-0ubuntu1.16.04.1) ...
Setting up juju (2.0~beta7-0ubuntu1.16.04.1) ...

Once that’s done, we can bootstrap a new “controller” using LXD. This means that Juju will not modify anything on your host, it will instead install its management service inside a LXD container.

Here, we’ll be creating a controller called “test” with:

stgraber@dakara:~$ juju bootstrap test localhost
Creating Juju controller "local.test" on localhost/localhost
Bootstrapping model "admin"
Starting new instance for initial controller
Launching instance
 - juju-745d1be3-e93d-41a2-80d4-fbe8714230dd-machine-0
Installing Juju agent on bootstrap instance
Preparing for Juju GUI 2.1.2 release installation
Waiting for address
Attempting to connect to 10.178.150.72:22
Logging to /var/log/cloud-init-output.log on remote host
Running apt-get update
Running apt-get upgrade
Installing package: curl
Installing package: cpu-checker
Installing package: bridge-utils
Installing package: cloud-utils
Installing package: cloud-image-utils
Installing package: tmux
Fetching tools: curl -sSfw 'tools from %{url_effective} downloaded: HTTP %{http_code}; time %{time_total}s; size %{size_download} bytes; speed %{speed_download} bytes/s ' --retry 10 -o $bin/tools.tar.gz <[https://streams.canonical.com/juju/tools/agent/2.0-beta7/juju-2.0-beta7-xenial-amd64.tgz]>
Bootstrapping Juju machine agent
Starting Juju machine agent (jujud-machine-0)
Bootstrap agent installed
Waiting for API to become available: upgrade in progress (upgrade in progress)
Waiting for API to become available: upgrade in progress (upgrade in progress)
Waiting for API to become available: upgrade in progress (upgrade in progress)
Bootstrap complete, local.test now available.

This should take about a minute, at which point you’ll see a new LXD container running:

stgraber@dakara:~$ lxc list juju-
+-----------------------------------------------------+---------+----------------------+------+------------+-----------+
|                         NAME                        |  STATE  |          IPV4        | IPV6 |    TYPE    | SNAPSHOTS |
+-----------------------------------------------------+---------+----------------------+------+------------+-----------+
| juju-745d1be3-e93d-41a2-80d4-fbe8714230dd-machine-0 | RUNNING | 10.178.150.72 (eth0) |      | PERSISTENT | 0         |
+-----------------------------------------------------+---------+----------------------+------+------------+-----------+

On the Juju side of things, you can confirm that it’s responding and that nothing is running yet:

stgraber@dakara:~$ juju status
[Services] 
NAME STATUS EXPOSED CHARM 

[Units] 
ID WORKLOAD-STATUS JUJU-STATUS VERSION MACHINE PORTS PUBLIC-ADDRESS MESSAGE 

[Machines] 
ID STATE DNS INS-ID SERIES AZ

You can also access the Juju GUI in your web browser with:

stgraber@dakara:~$ juju gui
Opening the Juju GUI in your browser.
If it does not open, open this URL:
https://10.178.150.72:17070/gui/97fa390d-96ad-44df-8b59-e15fdcfc636b/

Juju web UI

Though I prefer the command line so that’s what I’ll be using next.

Deploying a minecraft server

So lets start with something very trivial, just deploy a service that uses a single Juju unit in a single container.

stgraber@dakara:~$ juju deploy cs:trusty/minecraft
Added charm "cs:trusty/minecraft-3" to the model.
Deploying charm "cs:trusty/minecraft-3" with the charm series "trusty".

This should return pretty much immediately. It however doesn’t mean the service is already up and running. Instead you’ll want to look at “juju status”:

stgraber@dakara:~$ juju status
[Services] 
NAME STATUS EXPOSED CHARM 
minecraft maintenance false cs:trusty/minecraft-3 

[Units] 
ID WORKLOAD-STATUS JUJU-STATUS VERSION MACHINE PORTS PUBLIC-ADDRESS MESSAGE 
minecraft/1 maintenance executing 2.0-beta7 1 10.178.150.74 (install) Installing java 

[Machines] 
ID STATE DNS INS-ID SERIES AZ 
1 started 10.178.150.74 juju-97fa390d-96ad-44df-8b59-e15fdcfc636b-machine-1 trusty 

Here we can see it’s currently busy installing java in the LXD container it just created.

stgraber@dakara:~$ lxc list juju-
+-----------------------------------------------------+---------+----------------------+------+------------+-----------+
|                         NAME                        |  STATE  |          IPV4        | IPV6 |    TYPE    | SNAPSHOTS |
+-----------------------------------------------------+---------+----------------------+------+------------+-----------+
| juju-745d1be3-e93d-41a2-80d4-fbe8714230dd-machine-0 | RUNNING | 10.178.150.72 (eth0) |      | PERSISTENT | 0         |
+-----------------------------------------------------+---------+----------------------+------+------------+-----------+
| juju-97fa390d-96ad-44df-8b59-e15fdcfc636b-machine-1 | RUNNING | 10.178.150.74 (eth0) |      | PERSISTENT | 0         |
+-----------------------------------------------------+---------+----------------------+------+------------+-----------+

After a little while, the service will be done deploying as can be seen here:

stgraber@dakara:~$ juju status
[Services] 
NAME STATUS EXPOSED CHARM 
minecraft active false cs:trusty/minecraft-3 

[Units] 
ID WORKLOAD-STATUS JUJU-STATUS VERSION MACHINE PORTS PUBLIC-ADDRESS MESSAGE 
minecraft/1 active idle 2.0-beta7 1 25565/tcp 10.178.150.74 Ready 

[Machines] 
ID STATE DNS INS-ID SERIES AZ 
1 started 10.178.150.74 juju-97fa390d-96ad-44df-8b59-e15fdcfc636b-machine-1 trusty

At which point you can fire up your minecraft client, point it at 10.178.150.74 on port 25565 and play with your all new minecraft server!

When you want to get rid of it, just run:

stgraber@dakara:~$ juju destroy-service minecraft

Wait a few seconds and everything will be gone.

Deploying a more complex web application

Juju’s main focus is on modeling complex services and deploying them in a scallable way.

To better show that, lets deploy a Juju “bundle”. This bundle is a basic web service, made of a website, an API endpoint, a database, a static web server and a reverse proxy.

So that’s going to expand to 4, inter-connected LXD containers.

stgraber@dakara:~$ juju deploy cs:~charmers/bundle/web-infrastructure-in-a-box
added charm cs:~hp-discover/trusty/node-app-1
service api deployed (charm cs:~hp-discover/trusty/node-app-1 with the series "trusty" defined by the bundle)
annotations set for service api
added charm cs:trusty/mongodb-3
service mongodb deployed (charm cs:trusty/mongodb-3 with the series "trusty" defined by the bundle)
annotations set for service mongodb
added charm cs:~hp-discover/trusty/nginx-4
service nginx deployed (charm cs:~hp-discover/trusty/nginx-4 with the series "trusty" defined by the bundle)
annotations set for service nginx
added charm cs:~hp-discover/trusty/nginx-proxy-3
service nginx-proxy deployed (charm cs:~hp-discover/trusty/nginx-proxy-3 with the series "trusty" defined by the bundle)
annotations set for service nginx-proxy
added charm cs:~hp-discover/trusty/website-3
service website deployed (charm cs:~hp-discover/trusty/website-3 with the series "trusty" defined by the bundle)
annotations set for service website
related mongodb:database and api:mongodb
related website:nginx-engine and nginx:web-engine
related api:website and nginx-proxy:website
related nginx-proxy:website and website:website
added api/0 unit to new machine
added mongodb/0 unit to new machine
added nginx/0 unit to new machine
added nginx-proxy/0 unit to new machine
deployment of bundle "cs:~charmers/bundle/web-infrastructure-in-a-box-10" completed

A few seconds later, you’ll see all the LXD containers running:

stgraber@dakara:~$ lxc list juju-
+-----------------------------------------------------+---------+-----------------------+------+------------+-----------+
|                         NAME                        |  STATE  |           IPV4        | IPV6 |    TYPE    | SNAPSHOTS |
+-----------------------------------------------------+---------+-----------------------+------+------------+-----------+
| juju-745d1be3-e93d-41a2-80d4-fbe8714230dd-machine-0 | RUNNING | 10.178.150.72 (eth0)  |      | PERSISTENT | 0         |
+-----------------------------------------------------+---------+-----------------------+------+------------+-----------+
| juju-97fa390d-96ad-44df-8b59-e15fdcfc636b-machine-2 | RUNNING | 10.178.150.98 (eth0)  |      | PERSISTENT | 0         |
+-----------------------------------------------------+---------+-----------------------+------+------------+-----------+
| juju-97fa390d-96ad-44df-8b59-e15fdcfc636b-machine-3 | RUNNING | 10.178.150.29 (eth0)  |      | PERSISTENT | 0         |
+-----------------------------------------------------+---------+-----------------------+------+------------+-----------+
| juju-97fa390d-96ad-44df-8b59-e15fdcfc636b-machine-4 | RUNNING | 10.178.150.202 (eth0) |      | PERSISTENT | 0         |
+-----------------------------------------------------+---------+-----------------------+------+------------+-----------+
| juju-97fa390d-96ad-44df-8b59-e15fdcfc636b-machine-5 | RUNNING | 10.178.150.214 (eth0) |      | PERSISTENT | 0         |
+-----------------------------------------------------+---------+-----------------------+------+------------+-----------+

After a couple of minutes, all the services should be deployed and running:

stgraber@dakara:~$ juju status
[Services] 
NAME STATUS EXPOSED CHARM 
api unknown false cs:~hp-discover/trusty/node-app-1 
mongodb unknown false cs:trusty/mongodb-3 
nginx unknown false cs:~hp-discover/trusty/nginx-4 
nginx-proxy unknown false cs:~hp-discover/trusty/nginx-proxy-3 
website false cs:~hp-discover/trusty/website-3 

[Relations] 
SERVICE1 SERVICE2 RELATION TYPE 
api mongodb database regular 
api nginx-proxy website regular 
mongodb mongodb replica-set peer 
nginx website nginx-engine subordinate 
nginx-proxy website website regular 

[Units] 
ID WORKLOAD-STATUS JUJU-STATUS VERSION MACHINE PORTS PUBLIC-ADDRESS MESSAGE 
api/0 unknown idle 2.0-beta7 2 8000/tcp 10.178.150.98 
mongodb/0 unknown idle 2.0-beta7 3 27017/tcp,27019/tcp,27021/tcp,28017/tcp 10.178.150.29 
nginx-proxy/0 unknown idle 2.0-beta7 5 80/tcp 10.178.150.214 
nginx/0 unknown idle 2.0-beta7 4 10.178.150.202 
 website/0 unknown idle 2.0-beta7 10.178.150.202 

[Machines] 
ID STATE DNS INS-ID SERIES AZ 
2 started 10.178.150.98 juju-97fa390d-96ad-44df-8b59-e15fdcfc636b-machine-2 trusty 
3 started 10.178.150.29 juju-97fa390d-96ad-44df-8b59-e15fdcfc636b-machine-3 trusty 
4 started 10.178.150.202 juju-97fa390d-96ad-44df-8b59-e15fdcfc636b-machine-4 trusty 
5 started 10.178.150.214 juju-97fa390d-96ad-44df-8b59-e15fdcfc636b-machine-5 trusty

At which point, you can hit the reverse proxy on port 80 with http://10.178.150.214 and you’ll hit the Juju academy web service.

Juju Academy web service

Cleaning everything up

If you want to get rid of all the containers Juju created and don’t mind having to bootstrap again next time, the easiest way to destroy everything is with:

stgraber@dakara:~$ juju destroy-controller test --destroy-all-models
WARNING! This command will destroy the "local.test" controller.
This includes all machines, services, data and other resources.

Continue [y/N]? y
Destroying controller
Waiting for hosted model resources to be reclaimed
Waiting on 1 model, 4 machines, 5 services
Waiting on 1 model, 4 machines, 5 services
Waiting on 1 model, 4 machines, 5 services
Waiting on 1 model, 4 machines, 5 services
Waiting on 1 model, 4 machines, 5 services
Waiting on 1 model, 4 machines, 5 services
Waiting on 1 model, 4 machines
Waiting on 1 model, 4 machines
Waiting on 1 model, 4 machines
Waiting on 1 model, 4 machines
Waiting on 1 model, 4 machines
Waiting on 1 model, 4 machines
Waiting on 1 model, 2 machines
Waiting on 1 model
Waiting on 1 model
All hosted models reclaimed, cleaning up controller machines

And we can confirm that it’s all gone:

stgraber@dakara:~$ lxc list juju-
+------+-------+------+------+------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+------+-------+------+------+------+-----------+

Conclusion

Juju 2.0’s built-in LXD support makes for a very clean way to test a whole variety of services.

There are quite a few pre-made “bundles” for you to deploy in the Juju charm store and even more “charms” that you can use to piece together the architecture you want.

Juju with LXD is the perfect solution for easily developing anything from a small web service to a big scale out infrastructure, all on your own machine, without creating a mess on your system!

Extra information

The Juju website can be found at: http://www.ubuntu.com/cloud/juju
The Juju charm store is available at: https://jujucharms.com

The main LXD website is at: https://linuxcontainers.org/lxd
Development happens on Github at: https://github.com/lxc/lxd
Mailing-list support happens on: https://lists.linuxcontainers.org
IRC support happens in: #lxcontainers on irc.freenode.net
Try LXD online: https://linuxcontainers.org/lxd/try-it

Read more
facundo

Universidad y finales


El otro día estaba charlando con un amigo sobre algo relacionado a la Universidad, a una materia que cursé en la misma, y no me acordaba cuando la había rendido. En el momento no le dí importancia, pensé "cuando vuelvo a casa me fijo en la libreta universitaria".

Claro, nunca me fijé, porque la libreta está ahí escondida en un cajón de dificil acceso, el típico lugar donde alguien más o menos ordenado tiene los títulos viejos, certificados, papeles importantes diversos, y eso (los que no son medianamente ordenados en general no tienen puta idea donde están estas cosas).

Primera página de la libreta

Entones, se me ocurrió que, habiendo sido la Universidad una etapa tan importante en mi vida, podría tener la info de cuando rendí las materias mucho más a mano.

Busqué la libreta, pasé todas las materias (con fecha de final y la nota), y ahora guardo todo eso acá. Lástima que no tengo los nombres de las/los profesoras/es (me acuerdo algunos, pero la mayoría no...).

Read more
Daniel Holbach

Announcing the Snappy Playpen

With snaps and the store, it finally became easy again to publish software in Ubuntu. Snappy Playpen is a project in which we want to collaboratively snap software, learn from each other and document best-practices.

Snappy Playpen is on Github and it's where we want to work together on snapping new software. This will provide excellent examples to new users of snapcraft, we will be able to document best practices, learn from each other and create an incubator for new snaps to be added to the store.

Snappy Playpen won't be a collection of production-ready snaps, we are treating it a bit like a combination of research project and documentation.

If you are curious, just check out our main github page and read the docs there. It's easy and we're quite accessible. Find us on gitter, IRC or the mailing list to find out how to get involved.

You can get started at any time and contribute whatever you feel makes sense, but we want to host themed "sprint" weeks as well. If you have suggestions (e.g. a IoT-related week, a KDE-related week, server app, etc.), let us know. For those weeks we will make sure we have experts there to help us figure this out together.

Next week will be our first Snappy Playpen sprint and it will be a "free for all" week. This will help us to figure out the details and learn about what you all exactly want to do.

On Tuesday, 7th June 2016, we will make a big push and make sure our snapd and snapcraft engineers are there to answer questions and help figure out solutions together. Mark the day in your calendar and check out our docs to find out how to get started.

  • WHAT: Snappy playpen sprint
  • WHEN: Tuesday, 7th June 2016 all day
  • WHERE: Join us on gitter or IRC

Read more
liam zheng

Ubuntu手机现在迎来第十一个重要更新:OTA-11,这次更新的亮点主要为Wifi Display(无线投射模式),借助Wifi Display的功能用户可以体验无线投射屏幕加桌面融合(convergence)的巨大便利。只要将Ubuntu手机连接至显示器或电视,桌面版的Ubuntu模式即可使用,一个移动设备可变身集多窗口模式的全尺寸桌面。目前该功能仅支持魅族PRO5 Ubuntu版,后续还将支持其他型号Ubuntu手机。

Ubuntu手机今天迎来第十一个重要更新:OTA-11,这次更新主要的亮点为Wifi Display(屏幕无线投射),借助Wifi Display的功能用户可以体验无线投射屏幕加桌面融合(convergence)的巨大便利。只要将Ubuntu手机连接至显示器或电视(需要支持Miracast),桌面版的Ubuntu界面即可使用,一个移动设备将变身集多窗口模式的全尺寸桌面环境。目前该功能仅支持魅族PRO5 Ubuntu版,后续还将支持其他型号Ubuntu手机。

 

Wifi Display:点击观看

Wifi Display使用的是魅族PRO 5 Ubuntu版内建的p2p(peer-to-peer)连接方式启动Ubuntu桌面模式,如直接将手机通过Wifi连接显示器或电视,那么手机将充当触摸板的功能,如已连接蓝牙鼠标、键盘,则将拥有传统桌面模式的体验,重要的是,手机的短信、电话功能可展现在外接显示器上。

 

Scope支持自动横屏模式

在OTA-11以前,Unity 8 Dash的Scope只能竖屏显示。而在OTA-11更新后,Scope将可以横屏显示,对于喜欢横屏的用户来说又多一个选择。并且主页Scope(今日、Nearby)会在解锁屏幕前完成更新,解锁屏幕后可获取最新的信息。

 

新增繁体中文输入法

Ubuntu 手机OTA-11又一新特点是支持繁体中文输入法——注音键盘布局。可通过设置——语言&文字——键盘布局,选择注音输入法即可使用。

 

DGU让Scope、App自动适配多端显示

桌面融合(convergence)作为Ubuntu手机的杀手锏功能,已经让给很多经常背包的用户减轻不必要的负担,作为开发者而言,Unity 8用户界面将支持DGU(dynamic grid units),在开发应用和Scope时更简单,一次开发就可以在多个显示端自动适配。

 

平板:M10性能改善

OTA-11是BQ M10 Ubuntu版的第一个大版本更新,改善操控体验,图形处理,提示性能。

 

其他改进总结:

  • 地理位置服务改善,获取地理位置更加准确;

  • 网络管理器更新到1.2版,在上网时更加安全;

  • 应用程序支持多窗口显示(M10桌面融合);

  • UITK滚动条设计更新,Head支持副标题;

  • VPN支持用户名和密码认证;

  • 浏览器应用改进;支持google hangout,重新设计的权限提示对话框;

  • 在桌面融合模式蓝牙鼠标反应更敏捷;

  • 修复了以下bug:语言包翻译,性能问题,自定义通知声音

Read more
UbuntuTouch

有兴趣的朋友可以阅读我们全球开发者网站的文章"On Screen Keyboard tricks".里面讲了许多的东西.在今天的文章中,我们直接来一个活生生的例程来阐述这个问题.


Main.qml


import QtQuick 2.4
import Ubuntu.Components 1.3

/*!
    \brief MainView with a Label and Button elements.
*/

MainView {
    // objectName for functional testing purposes (autopilot-qt5)
    objectName: "mainView"

    // Note! applicationName needs to match the "name" field of the click manifest
    applicationName: "osk.liu-xiao-guo"

    width: units.gu(60)
    height: units.gu(85)

    // anchorToKeyboard: true

    Page {
        title: i18n.tr("onscreenkeyboard")
        anchors.fill: parent

        Flickable {
            id: sampleFlickable

            clip: true
            contentHeight: mainColumn.height + units.gu(5)
            anchors {
                top: parent.top
                left: parent.left
                right: parent.right
                bottom: createButton.top
                bottomMargin: units.gu(2)
            }

            Column {
                id: mainColumn

                spacing: units.gu(2)

                anchors {
                    top: parent.top
                    left: parent.left
                    right: parent.right
                    margins: units.gu(2)
                }

                TextField {
                    id: username
                    width: parent.width
                    placeholderText: "username"
                }

                TextField {
                    id: password
                    width: parent.width
                    placeholderText: "password"
                }

                TextField {
                    id: email
                    width: parent.width
                    placeholderText: "email"
                }
            }
        }

        Button {
            id: createButton
            text: "Create Account"
            anchors {
                horizontalCenter: parent.horizontalCenter
                bottom: parent.bottom
                margins: units.gu(2)
            }
            onClicked: {
                console.log("it is clicked")
            }
        }
    }
}

在上面的例程中,我们有意识地把:

    anchorToKeyboard: true

注释掉,我们可以运行我们的应用:


从上面的截图中可以看出来,当我们点击最上面的任何一个输入框时,我们最下面的"Createt Account"按钮就被键盘所在的位置遮住了.那么我们怎么才能可以见到我们的按钮呢?答案就是在我们的MainView中,把如下的开关打开:

    anchorToKeyboard: true

再次重新运行我们的应用:



从上面我们可以看出来.当我们点击email进行输入的时候,"Create Account"按钮也自动跑到我们键盘的上面.这样当我们输入完我们的内容的时候,我们可以直接按下按钮来进行创建一个账号,而不用先把键盘弄消失掉,再提交.

整个项目的源码在:https://github.com/liu-xiao-guo/osk

我们来用另外一个例程来展示OSK的用法:

Main.qml

import QtQuick 2.4
import Ubuntu.Components 1.3

MainView {
    // objectName for functional testing purposes (autopilot-qt5)
    objectName: "mainView"

    // Note! applicationName needs to match the "name" field of the click manifest
    applicationName: "osk1.liu-xiao-guo"

    width: units.gu(100)
    height: units.gu(75)

  //  anchorToKeyboard: true

    Page {
        header: PageHeader {
            id: pageHeader
            title: i18n.tr("osk1")
            StyleHints {
                foregroundColor: UbuntuColors.orange
                backgroundColor: UbuntuColors.porcelain
                dividerColor: UbuntuColors.slate
            }
        }

        TextField {
            anchors.bottom: parent.bottom
            anchors.horizontalCenter: parent.horizontalCenter
            anchors.bottomMargin: units.gu(2)
            placeholderText: "please input something"
        }
    }
}

在上面的例程中,当我们注释掉:

    anchorToKeyboard: true

运行我们的应用,并在最下面的输入框中点击进行输入:

  

从上面可以看出来,当我们进行输入的时候,我们的输入框被键盘挡住了.我们看不见我们的输入框.而当我们把下面的属性设为真时:

  anchorToKeyboard: true

在重新运行我们的应用:

  



从上面我们可以看出来,当我们输入的时候我们可以看见我们的输入框,并可以输入为我们所需要的内容.

整个项目的源码在:https://github.com/liu-xiao-guo/osk1



作者:UbuntuTouch 发表于2016/4/18 13:54:51 原文链接
阅读:269 评论:0 查看评论

Read more
UbuntuTouch

细心开发者如果发现我的以前开发的应用,主页面能够切换的地方,我放置了一个向右的箭头.比如在文章"从零开始创建一个Ubuntu应用 -- 一个小小的RSS阅读器 (1)"最下面的图片中,我们可以看到在列表中,有一个向右的箭头.



在我们的Ubuntu应用中,我们可以利用ListItemLayout来作为我们列表中的每一项的delegate.在这种情况下,我们可以充分利用ProgressionSlot来为我们添加上一个向右的">"符号.比如在下面的例子中:


Main.qml


import QtQuick 2.4
import Ubuntu.Components 1.3

MainView {
    // objectName for functional testing purposes (autopilot-qt5)
    objectName: "mainView"

    // Note! applicationName needs to match the "name" field of the click manifest
    applicationName: "progressionslot.liu-xiao-guo"

    width: units.gu(60)
    height: units.gu(85)

    Page {
        header: PageHeader {
            id: pageHeader
            title: i18n.tr("progressionslot")
            StyleHints {
                foregroundColor: UbuntuColors.orange
                backgroundColor: UbuntuColors.porcelain
                dividerColor: UbuntuColors.slate
            }
        }

        ListItem {
            anchors {
                left: parent.leftt
                right: parent.right
                top: parent.header.bottom
            }

            height: layout.height + (divider.visible ? divider.height : 0)
            ListItemLayout {
                id: layout
                title.text: "Hello developers!"
                subtitle.text: "I'm a subtitle, I'm tiny!"
                summary.text: "Ubuntu!"
                CheckBox { SlotsLayout.position: SlotsLayout.Leading }
                Icon {
                    name: "message"
                    SlotsLayout.position: SlotsLayout.Trailing;
                    width: units.gu(2)
                }

                ProgressionSlot {}
            }
        }
    }
}

我们利用了一个ProgressionSlot.这样我们的ListItem显示为:



我们可以在上面的显示中,清楚地看见一个向右的箭头.这就是使用ProgressionSlot所带来的.


作者:UbuntuTouch 发表于2016/4/29 11:04:55 原文链接
阅读:303 评论:0 查看评论

Read more
UbuntuTouch

[原]利用SVG在QML中画图

在我先前的文章"在QML应用中使用Canvas来画图"中,我展示如何利用QML中的Canvas来画我们的曲线.今天在我们的文章中,我们来展示如何利用SVG在我们的例程中画我们所需要的曲线.


我们可以直接使用一个已经存在的SVG画画库simple-svg.它的源码位于"https://code.google.com/archive/p/simple-svg/downloads".对于一下开发者来说可能需要VPN才可以下载哦.


我们可以利用我们的SDK中提供的一个标准的"QML App with C++ plugin (qmake)"来创建一个简单的模版.同时,我们修改我们的plugin的代码如下:

mytype.h


#ifndef MYTYPE_H
#define MYTYPE_H

#include <QObject>

class MyType : public QObject
{
    Q_OBJECT
    Q_PROPERTY( QString helloWorld READ helloWorld WRITE setHelloWorld NOTIFY helloWorldChanged )

public:
    explicit MyType(QObject *parent = 0);
    ~MyType();
    Q_INVOKABLE void draw(const int &width, const int &height, const QString &array);

Q_SIGNALS:
    void helloWorldChanged();

protected:
    QString helloWorld() { return m_message; }
    void setHelloWorld(QString msg) { m_message = msg; Q_EMIT helloWorldChanged(); }

    QString m_message;
};

#endif // MYTYPE_H

在上面我们添加了一个叫做"draw"的方法.它的定义如下:

mytype.cpp


#include "mytype.h"
#include "simple_svg.h"

using namespace svg;

MyType::MyType(QObject *parent) :
    QObject(parent),
    m_message("")
{

}

MyType::~MyType() {

}

void MyType::draw(const int &width, const int &height, const QString &array)
{
    // Create the SVG doc
    Dimensions dimensions(width, height);
    Document doc("../svggraph/svggraph/graph.svg", Layout(dimensions, Layout::BottomLeft));

    // Parse our string into an array
    std::istringstream buf(array.toStdString());
    std::istream_iterator<std::string> beg(buf), end;
    std::vector<std::string> tokens(beg, end);

    // Create a line
    Polyline polyline_a(Stroke(1.5, Color::Cyan));

    // Iterate over our array to define line start/end points
    for( int a = 0; a < tokens.size(); a = a + 1 )
    {
        if (tokens.size() < 2) {
            polyline_a << Point(width/(tokens.size())*(a), atoi(tokens[a].c_str())) << Point(width/(tokens.size())*(a+1), atoi(tokens[a].c_str()));
        } else {
            polyline_a << Point(width/(tokens.size()-1)*(a), atoi(tokens[a].c_str()));
        }
    }
    doc << polyline_a;

    // Save the doc
    doc.save();
}

在这里,我们把从地址https://code.google.com/archive/p/simple-svg/downloads下载的文件重新命令为"simple_svg.h",并把它存于位于plugins所在目录的根目录中,也即:

svggraph/backend/Svggraph

我们可以重新编译我们的应用.

在我们的Main.qml中,我们可以利用我们刚刚创建的plugin来画我们的UI.和先前不同的是,这里,我们使用一个叫做Image的而不是一个Canvas.

Main.qml

import QtQuick 2.4
import Ubuntu.Components 1.3
import Svggraph 1.0
/*!
    \brief MainView with a Label and Button elements.
*/

MainView {
    // objectName for functional testing purposes (autopilot-qt5)
    objectName: "mainView"

    // Note! applicationName needs to match the "name" field of the click manifest
    applicationName: "svggraph.liu-xiao-guo"

    width: units.gu(60)
    height: units.gu(85)

    MyType {
        id: myType
    }

    Page {
        id: page
        header: PageHeader {
            id: pageHeader
            title: i18n.tr("svggraph")
            StyleHints {
                foregroundColor: UbuntuColors.orange
                backgroundColor: UbuntuColors.porcelain
                dividerColor: UbuntuColors.slate
            }
        }

        Rectangle {
            anchors {
                top:page.header.bottom
                left: page.header.left
                right: page.header.right
            }
            height: parent.height - page.header.height

            TextField{
                id:txt
                width:parent.width - units.gu(4)
                anchors.top:parent.top
                anchors.horizontalCenter:parent.horizontalCenter
                anchors.margins:units.gu(2)
                text: "0 10 50 80 60 90"
            }
            Row {
                anchors.top:txt.bottom
                anchors.horizontalCenter: parent.horizontalCenter
                anchors.margins: units.gu(2)
                spacing: units.gu(2)
                Button {
                    id:drawButton
                    anchors.margins:units.gu(2)
                    text:i18n.tr("Draw")
                    enabled:(txt.length)
                    color: UbuntuColors.orange
                    onClicked: {
                        myType.draw(page.width, page.height, txt.text)
                        img.source = ""
                        img.source = Qt.resolvedUrl("graph.svg")
                    }
                }
                Button {
                    id:clearButton
                    anchors.margins:units.gu(2)
                    text:i18n.tr("Clear")
                    onClicked: {
                        myType.draw(page.width, page.height, "")
                        img.source = ""
                        img.source = Qt.resolvedUrl("graph.svg")
                    }
                }
            }
            Image {
                id:img
                anchors.fill:parent
                anchors.margins:units.gu(2)
                cache:false
                source: Qt.resolvedUrl("graph.svg")
            }
        }
    }
}

在这里,我们通过按钮"Draw"把我们所需要的数据传入到plugin中,并生产graph.svg文件,并在UI的Image中得以显示:






整个项目的源码在:https://github.com/liu-xiao-guo/svggraph
作者:UbuntuTouch 发表于2016/4/25 10:36:03 原文链接
阅读:198 评论:0 查看评论

Read more
UbuntuTouch

我们知道在许多的项目中,当切换到一个页面时我们需要对一些资源进行监控.每当发送事件改变时,我们需要进行更新我们的页面.当然每当我们离开我们的页面时,我们就不想做这样的动作.我们可以取消或释放我们所需要的资源以节省资源.当我们需要这么做的时候,我们希望得到页面切换时的事件这样我们可以在合适的时机做出合适的动作.Qt中的Component.incubateObject()为我们提供了这样一个监控的机制.


下面我们用一个简单的例程来说明这个问题:

Main.qml


import QtQuick 2.4
import Ubuntu.Components 1.3

MainView {
    id: mainview
    // objectName for functional testing purposes (autopilot-qt5)
    objectName: "mainView"

    // Note! applicationName needs to match the "name" field of the click manifest
    applicationName: "pagedestroyevent.liu-xiao-guo"

    width: units.gu(60)
    height: units.gu(85)

    property int index: 0

    Component {
        id: page2Component

        Page {
            id: page


            header: PageHeader {
                id: header
                title: "Second Page"
            }

            Column {
                anchors.centerIn: parent
                spacing: units.gu(5)

                Text {
                    text: "Page: " + index
                }

                Button {
                    text: "Close me"
                    onClicked: pageStack.removePages(pageStack.primaryPage);
                }
            }
        }
    }

    AdaptivePageLayout {
        id: pageLayout
        anchors.fill: parent
        primaryPage: Page {
            header: PageHeader {
                title: "Primary Page"
                flickable: listView
            }

            ListView {
                id: listView
                anchors.fill: parent
                model: 10
                delegate: ListItem {
                    Label { text: modelData }
                    onClicked: {
                        mainview.index = index
                        var incubator = pageLayout.addPageToNextColumn(pageLayout.primaryPage, page2Component);
                        if (incubator && incubator.status === Component.Loading) {
                            incubator.onStatusChanged = function(status) {
                                if (status === Component.Ready) {
                                    // connect page's destruction to decrement model
                                    incubator.object.Component.destruction.connect(function() {
                                        console.log("it is destructed! " + index)
                                    });
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

在上面的例程中我们运用AdaptivePageLayout来实现我们的布局.运行我们的应用:

  



每当我们打开ListView中的一项的时候,我们通过:
   var incubator = pageLayout.addPageToNextColumn(pageLayout.primaryPage, page2Component);
把我们的新的一页加入到pageStack中,同时,我们可以利用incubator对刚刚加入的页面进行lifecycle的管理:

                        if (incubator && incubator.status === Component.Loading) {
                            incubator.onStatusChanged = function(status) {
                                if (status === Component.Ready) {
                                    // connect page's destruction to decrement model
                                    incubator.object.Component.destruction.connect(function() {
                                        console.log("it is destructed! " + index)
                                    });
                                }
                            }
                        }

每当一个页面被销毁时,我们将收到一个输出:

qml: it is destructed! 0
qml: it is destructed! 5
qml: it is destructed! 5
qml: it is destructed! 3
qml: it is destructed! 0
qml: it is destructed! 4
qml: it is destructed! 7

就像我们上面显示的那样.我们可以在这个输出的地方加入任何一个我们想要做的东西,比如释放内存及取消监视事件等.

作者:UbuntuTouch 发表于2016/4/26 11:20:08 原文链接
阅读:171 评论:0 查看评论

Read more
UbuntuTouch

[原]Ubnutu手机中的Theme颜色

在我们设计应用时,我们可能很想知道所有在Ubuntu手机设计中的Theme颜色.在今天的例程中,我们将动态地检测我们系统里所有的Theme的颜色,并显示它们.开发者可以充分利用这些颜色在自己的设计中.在我们的设计中,开发者可以通过向左或向右滑动手势来导航列表中的内容.这个项目的设计有点像是一个Property browser.可以扩展到其它的项目中.关于Ubuntu手机中的Theme更多的知识,请阅读https://developer.ubuntu.com/en/phone/apps/qml/tutorials/ubuntu-ui-toolkit-palette/.该应用可以在Ubuntu商店中下载"ThemeViewer".


   


   


Main.qml


import QtQuick 2.4
import Ubuntu.Components 1.3
import Qt.labs.settings 1.0

MainView {
    // objectName for functional testing purposes (autopilot-qt5)
    objectName: "mainView"

    // Note! applicationName needs to match the "name" field of the click manifest
    applicationName: "themeviewer.liu-xiao-guo"

    width: units.gu(60)
    height: units.gu(85)

    property var props: [theme]
    property var propnames : ["theme"]

    ListModel {
        id: mymodel
    }

    Settings {
        id: settings
        property bool selectedAmbiance: true
    }

    function goUp() {
        if ( propnames.length > 1) {
            // We only do it when there is more than one item
            propnames.pop();
            header.text = propnames.join(".");
            props.pop();
            getProperties(props[props.length -1])
            console.log("swipe left: " + propnames)
        }
    }

    function getProperties(obj) {
        mymodel.clear();

        var keys = Object.keys(obj);
        for(var i = 0; i < keys.length; i++) {
            var key = keys[i];
            var type = typeof obj[key];
            console.log(key + ' : ' + obj[key] + " " + type);

            if ( type === 'object' && obj[key] ) {
                if ( propnames.length === 3 ) {
                    mymodel.append({"name": key, "value": ""+obj[key] })
                } else {
                    mymodel.append({"name": key, "value": "white" })
                }
            }
        }
    }

    Page {
        id: page
        header: PageHeader {
            id: pageHeader
            title: i18n.tr("Theme Viewer")
            trailingActionBar.actions: [
                Action {
                    iconSource: settings.selectedAmbiance ?
                                "images/ambiance.png" : "images/dark.png"
                    text: "Ambiance"
                    onTriggered: {
                        settings.selectedAmbiance = !settings.selectedAmbiance

                        theme.name = (settings.selectedAmbiance ?
                                          "Ubuntu.Components.Themes.Ambiance" :
                                          "Ubuntu.Components.Themes.SuruDark" )

                        // We need to do it from the very beginning
                        props = [theme]
                        propnames = ["theme"]
                        header.text = propnames.join(".")
                        getProperties(props[props.length -1])
                    }
                }
            ]

            StyleHints {
                foregroundColor: UbuntuColors.orange
                backgroundColor: UbuntuColors.porcelain
                dividerColor: UbuntuColors.slate
            }
        }

        SystemPalette { id: __palette }

        Component {
            id: delegate
            Rectangle {
                width: parent.width
                height: propname.height * 1.7
                color: "transparent"

                Rectangle {
                    height: parent.height
                    width: parent.width*.2
                    anchors {
                        right: parent.right
                        top: parent.top
                    }
                    color: value
                    visible: propnames.length === 3
                }

                Label {
                    id: propname
                    text: name
                    fontSize: "x-large"
                    anchors.verticalCenter: parent.verticalCenter
                }

                MouseArea {
                    id: mouseRegion
                    anchors.fill: parent

                    onDoubleClicked: {
                        props.push(props[props.length -1][propname.text])
                        propnames.push(propname.text)
                        header.text = propnames.join(".")
                        getProperties(props[props.length -1])
                    }

                    onClicked: {
                        list.currentIndex = index;
                    }
                }

                SwipeArea {
                    id: swiperight
                    anchors.fill: parent
                    direction: SwipeArea.Rightwards

                    onDraggingChanged: {
                        if ( dragging ) {
                            console.log("swipe right: " + propname.text)
                            props.push(props[props.length -1][propname.text])
                            propnames.push(propname.text)
                            header.text = propnames.join(".")
                            getProperties(props[props.length -1])
                        }
                    }
                }
            }
        }

        Column {
            anchors {
                left: parent.left
                right: parent.right
                bottom: parent.bottom
                top: page.header.bottom
            }

            Row {
                width: parent.width
                height: header.height

                Button {
                    id: upButton
                    height: parent.height
                    width: units.gu(5)
                    iconSource: "qrc:///images/up.png"
                    onClicked:  {
                        goUp()
                    }
                }

                Label {
                    id: header
                    text: { return propnames.join(".") }
                    fontSize: "large"
                }

            }

            UbuntuListView {
                id: list
                clip:true
                width: page.width
                height: page.height - header.height
                focus: true
                model: mymodel
                highlight: Rectangle {
                    color: __palette.midlight
                    border.color: Qt.darker(__palette.window, 1.3)
                }
                highlightMoveDuration: -1
                highlightMoveVelocity: -1
                highlightFollowsCurrentItem: true
                delegate: delegate
            }

            Component.onCompleted: {
                getProperties(props[props.length -1])
            }
        }
    }

    SwipeArea {
        id: swipeleft
        direction:  SwipeArea.Leftwards
        anchors.fill: parent

        onDraggingChanged: {
            if ( dragging ) {
                goUp()
            }
        }
    }
}

整个项目的源码在:https://github.com/liu-xiao-guo/themeviewer
作者:UbuntuTouch 发表于2016/4/28 15:03:32 原文链接
阅读:276 评论:0 查看评论

Read more
UbuntuTouch

很多开发者可能希望能够在不改变现有的Ubuntu Toolkit中的控件的情况下,有个性地来改变一些属性.这样使得自己的界面更加个性化.目前我们在我们的官方网址可以查看到我们已经有的一些Style的一些控件.这个列表并不完善.更加详细的列表在地址可以看到.


下面,我们来用一个具体的例子来说明如何是用这些API来个性化我们的应用的:


Main.qml


import QtQuick 2.4
import Ubuntu.Components 1.3
import Ubuntu.Components.Themes 1.3
import Ubuntu.Components.Styles 1.3

MainView {
    // objectName for functional testing purposes (autopilot-qt5)
    objectName: "mainView"

    // Note! applicationName needs to match the "name" field of the click manifest
    applicationName: "style.liu-xiao-guo"

    width: units.gu(60)
    height: units.gu(85)

    Action {
        id: action1
        text: "action 1"
        iconName: "compose"
        onTriggered: print("one!")
    }

    Page {
        header: PageHeader {
            id: pageHeader
            title: i18n.tr("pageheaderstyle")

            style: PageHeaderStyle {
                foregroundColor: UbuntuColors.orange
                backgroundColor: UbuntuColors.porcelain
                dividerColor: UbuntuColors.slate
                contentHeight: units.gu(10)
                Label {
                    anchors.centerIn: parent
                    fontSize: "x-large"
                    text: styledItem.title
                }
                implicitHeight: contentHeight
            }
        }

        Image {
            id: pressed
            source: "images/pressed.jpg"
            visible: false
        }

        Image {
            id: unpressed
            source: "images/unpressed.jpg"
            visible: false
        }

        Column {
            anchors.centerIn: parent
            spacing: units.gu(5)

            Button {
                id: button1
                width: units.gu(40)
                height: units.gu(15)
                text: "Nice"
                StyleHints {
                    defaultColor: button1.pressed ? "blue" : "red"
                }
            }

            Button {
                id: button2
                width: units.gu(40)
                height: units.gu(15)
                text: "Nice"
                StyleHints {
                    backgroundSource: button2.pressed ? pressed : unpressed
                }
            }
        }
    }
}

在上面的代码中,我们使用了PageHeaderStyle来个性化我们的page header.我们它的高度设置为units.gu(10),同时我们也让我们的文字居中.

在下面的代码中,我们利用StyleHints来修改我们已经在使用的style的一些属性.比如:

            Button {
                id: button1
                width: units.gu(40)
                height: units.gu(15)
                text: "Nice"
                StyleHints {
                    defaultColor: button1.pressed ? "blue" : "red"
                }
            }

在上面的代码中,当我们的按钮按下时,颜色会变为蓝色而不是通常状态下的红色:

 

另外,如下的代码可以使得我们的按钮在按下,和不按下的情况下显示不同的图片:

            Button {
                id: button2
                width: units.gu(40)
                height: units.gu(15)
                text: "Nice"
                StyleHints {
                    backgroundSource: button2.pressed ? pressed : unpressed
                }
            }


 

关于ButtonStyle的更多介绍请参阅连接

整个项目的源码在:https://github.com/liu-xiao-guo/style


作者:UbuntuTouch 发表于2016/5/3 11:50:27 原文链接
阅读:206 评论:0 查看评论

Read more
Zoltán Balogh

Can I haz MainView in a Window?

When using Unity8 these days connecting a Bluetooth mouse to a device enables windowed mode. Another option is to connect an external monitor via HDMI and most recently on some devices wireless displays. This raises a few questions on the API side of things.

Apps are currently advised to use a MainView as the root item, which can have a width and a height used as the window dimensions in a windowed environment - on phones and tablets by default all apps are always full screen. As soon as users can freely resize the window, some apps may not look great anymore - QtQuick.Window solves this by providing minimum/maximum/Width/Height properties. Another question is what title is used for the window - as soon as there is more than one Page that's no longer obvious and it's actually somewhat redundant.

So what can we do now?

There’s two ways to sort this that we’ll be discussing here. One way is to in fact go ahead and use MainView, which is just an Item, and put it inside a Window. That’s perfectly fine to do and that’s a good stop-gap for any apps affected now. To the user the outcome is almost the same, except the title and sizing can be customized behind the scenes.

import QtQuick 2.4
import QtQuick.Window 2.2
import Ubuntu.Components 1.3
Window {
    title: "Hello World"
    minimumWidth: units.gu(30)
    minimumHeight: units.gu(50)
    maximumWidth: units.gu(90)
    maximumHeight: units.gu(120)
    MainView {
        applicationName: "Hello World"
    }
}

From here on after things work exactly the same way they did before. And this is something that will continue to work in the future.

A challenger appears

That said, there’s another way under discussion. What if there was a new MainWindow component that could replace the MainView and provide the missing features out of the box? Code would be simpler. Is it worth it, though, just to save some lines of code you might wonder? Yes actually. It is worth it when performance enters the picture.

As it is now, MainView does many different things. It displays a header for starters - that is, if you’re not using AdaptivePageLayout to implement convergence. It also has automaticOrientation API, something the shell does a much better job of these days. And it handles actions, which are, like the header, part of each Page now. It’s still doing a good job at things we need, like setting up folders for confinement (config, cache, localization) and making space for the OSK (in the form of anchorsToKeyboard). So in short, there’s several internals to re-consider if we had a chance to replace it.

Even more drastic would be the impact of implementing properties in MainWindow that right now are context properties. “units” and “theme” are very useful in so many ways and at the same time by design super slow because of how QML processes them. A new toplevel component in C++ could provide regular object properties without the overhead potentially speeding up every single use of those properties throughout the application as well as the components using them behind the scenes.

Let’s be realistic, however, these are ideas that need discussion, API design and planning. None of this is going to be available tomorrow or next week. So by all means, engage in the discussions, maybe there’s more use cases to consider, other approaches, it’s the one component virtually every app uses so we better do a good job coming up with a worthy successor.

Read more
Prakash

The public cloud services market in the country is projected to grow 30.4 per cent to reach USD 1.26 billion this year as organisations are pursuing a digital business strategy, Gartner said today. According to the research firm, public cloud services market, which stood at USD 968.1 million in 2015, will reach USD 3.52 billion by 2020.

Read More: http://www.financialexpress.com/article/industry/tech/public-cloud-services-in-india-to-reach-1-26-billion-this-year-gartner/249120/

Read more
Craig Bender

Hello world!

Welcome to Canonical Voices. This is your first post. Edit or delete it, then start blogging!

Read more
Grazina Borosko

Last year we were working on OOBE redesign with the aim to improve first user experience with Ubuntu phone. Now the Design Team is working on the second part of this project which we call Edge Education.

The purpose of Edge Education is to aid discoverability and to educate users into using them naturally. For example, did you know what you can access the whole system by swiping from the edges of the screen.

How many edges Ubuntu phone has?

At the moment, the Ubuntu phone has four edges that can be interacted with in six ways.

Left short swipe

If you short swipe across the left edge you will open the launcher.

Left long swipe

You can quickly come back from any app to the Dash by a long left swipe.

Top swipe

Swiping from the top edge will give you access to indicator menus.

Right long swipe

Long swipe from the right edge will open the switcher to let you move between open apps.

Right short swipe

Swiping from the right edge you will switch between your current and previous app (ALT-TAB interaction).

Bottom swipe (app specific)

Swiping from the bottom edge brings you different functionality depending if you are in app or scope. Not all apps has a bottom edge. If an app has a bottom edge you will know this by seeing a bottom edge hint. For example, you can add a new contact by swiping from the bottom edge in the Contacts app. By doing bottom edge swipe in the scopes you can quickly favourite and unfavorite your scopes.

Read more