Mobile Zone is brought to you in partnership with:

Den is a DZone Zone Leader and has posted 460 posts at DZone. You can read more from them at their website. View Full User Profile

Flickr API for Windows Phone 7 – Part 10 – Groups – Base Methods

10.12.2010
| 6087 views |
  • submit to reddit

Flickr provides functionality to create groups of people with similar interests. For example, someone might be an avid automobile fan, so that person creates a group where he and other people with the same interests post pictures of cars and everything related to them. Obviously, you can either create your own group or join someone else’s. And of course, you can add your photos to a group (although with specific quantity restrictions).

Before going any further with code, let’s take a look at what kinds of groups are there.

•    Public groups – anyone can join and see the content provided by this group. Perfect for various common interest groups that relate to a large number of people (e.g. cars, like I mentioned above).
•    Public, but only accepting new members by invitation – anyone can view group content but not everyone can join. This is a very nice type of groups for specific events. For example, a conference – everyone can see what it looked like but only people who attended the event are approved as members by the group administrator.
•    Private groups –this is the kind of groups you’d like to create to share pictures only with your family or with a limited circle of friends. An important thing to remember here is that once a group is set to be private, you cannot make it public.

Flickr API is somewhat limited when it comes to creating groups – in fact, you are not able to create a group via the API, but you are able to add your pictures to a group pool if allowed to do so (depending on the group restrictions).

There are three categories of operations that can be applied to groups:

•    groups – contains the method calls that will be executed to get the information about existing groups.
•    groups.members – contains the method calls that will be called to get the information regarding members who joined specific groups.
•    groups.pools – allows the calling user to manage contributions to a group pool (e.g. adding or removing pictures)

In this article I will be covering only methods included in the base groups category. Compared to my previous implementation, I decided to change the class structure a bit here, so it should follow the model shown in the image below.

This is achieved fairly easy by using this class skeleton:

public static class Groups
{
    public static class Members
    {

    }

    public static class Pools
    {

    }
}

Notice that Members and Pools are nested classes and are static – users won’t be able to instantiate them, so you will have to work with one method call at a time. The general template applied before is transferred here as well. The first thing I do is create an instance of HelperDelegate - that will be handling post-processing operations when the method response is received.

private HelperDelegate helperDelegateInstance;

There is also the string property that will contain the result of the last operation – the JSON-formatted response:

public string LastGroupResult { get; set; }

This all goes in the main Groups class and will be later on referenced in every nested class, so there is no need to include these components in nested classes.

Let’s start with the main container class – Groups. There should be three methods implemented here:

•    getInfo – gets the info related to a specific group
•    browse – allows browsing groups inside a group category
•    search – search for groups

getInfo is pretty basic:

public enum Language
{
    English,
    German,
    Spanish,
    French,
    Italian,
    Korean,
    Portuguese,
    TraditionalChinese
}

public static void GetList(string apiKey, string groupID, Language language, HelperDelegate helperDelegate)
{
    helperDelegateInstance = helperDelegate;

    WebClient client = new WebClient();
    client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
    string URL = string.Format("http://www.flickr.com/services/rest/?method=flickr.groups.getInfo&api_key={0}&format=json&group_id={1}〈=",
            apiKey,groupID);

    switch (language)
    {
        case Language.English:
            {
                URL += "en-us";
                break;
            }
        case Language.German:
            {
                URL += "de-de";
                break;
            }
        case Language.Spanish:
            {
                URL += "es-us";
                break;
            }
        case Language.French:
            {
                URL += "fr-fr";
                break;
            }
        case Language.Italian:
            {
                URL += "it-it";
                break;
            }
        case Language.Korean:
            {
                URL += "ko-kr";
                break;
            }
        case Language.Portuguese:
            {
                URL += "pt-br";
                break;
            }
        case Language.TraditionalChinese:
            {
                URL += "zh-hk";
                break;
            }
    }

    client.DownloadStringAsync(new Uri(URL));
}

The response is available in several languages, so that’s why there is an enum that specifies the possible response language. If you look at the GetInfo structure, you will see that eventually, depending on the enum value selected, the language is passed as a parameter in the existing URL. The abbreviation is taken from the Flickr Feeds language conventions. And I think that you are pretty familiar with the client_DownloadStringCompleted event handler:

static void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
    LastGroupResult = e.Result;
    helperDelegateInstance();
}

Try this method out in your application:

Core.Groups.GetList(apiKey, "1136987@N22", Core.Groups.Language.English, () =>
{
    Debug.WriteLine(Core.Groups.LastGroupResult);
});

1136987@N22 is the group ID for “Montgomery County, Kansas”, so the response you will get should be very similar to this:

jsonFlickrApi({"group":{"id":"1136987@N22", "iconserver":"3661", "iconfarm":4, "name":{"_content":"Montgomery County Kansas"}, "description":{"_content":"Photos of Montgomery County Kansas"}, "members":{"_content":"9"}, "privacy":{"_content":"3"}, "lang":null, "ispoolmoderated":0, "blast":{"_content":"Photos taken of  people and places in Montgomery County Kansas.", "date_blast_added":"1242074108", "user_id":"15300634"}, "throttle":{"mode":"none"}, "restrictions":{"photos_ok":1, "videos_ok":1, "images_ok":1, "screens_ok":1, "art_ok":1, "safe_ok":1, "moderate_ok":0, "restricted_ok":0, "has_geo":0}}, "stat":"ok"})

A bit messy, but later on I will show you how to pick the useful bits out of this set. Searching through groups shouldn’t be much of an issue – all you have to do is call the Search method that is implemented like this:

public static void Search(string apiKey, string text, HelperDelegate helperDelegate,string page ="",string perPage="")
{
    helperDelegateInstance = helperDelegate;

    WebClient client = new WebClient();
    client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
    string URL = string.Format("http://www.flickr.com/services/rest/?method=flickr.groups.search&api_key={0}&format=json&text={1}",
            apiKey,text);

    if (page != "")
        URL += "&page=" + page;
    if (perPage != "")
        URL += "&per_page=" + perPage;

    client.DownloadStringAsync(new Uri(URL));
}

text is the search parameter. So, for example, if I would want to search for groups about cats, I can do call the method:

Core.Groups.Search(apiKey, "cats", () =>
{
    Debug.WriteLine(Core.Groups.LastGroupResult);
});

And get the result:

jsonFlickrApi({"groups":{"page":1, "pages":244, "perpage":100, "total":"24338", "group":[{"nsid":"43775233@N00", "name":"Best of Cats (Invited Photos) - Vote Best Of September+Comment", "eighteenplus":0}, {"nsid":"97797733@N00", "name":"LOL CATS -INVITED PHOTOS ONLY!  New Icon Contest Going on NOW!", "eighteenplus":0}, {"nsid":"618157@N23", "name":"Multiple Cats", "eighteenplus":0}, {"nsid":"661812@N25", "name":"ALL CATS ^..^ NO PEOPLE", "eighteenplus":0}, {"nsid":"709202@N21", "name":"ALL CATS ALLOWED!!!", "eighteenplus":0}, {"nsid":"75601600@N00", "name":"Somebody else's cat", "eighteenplus":0}, {"nsid":"685375@N21", "name":"Cat's Meawww*Post 1 award 3~", "eighteenplus":0}, {"nsid":"26069902@N00", …

The returned JSON document is too long so you will not see the complete result in the Output window and I also didn’t want to fill the entire article with it, but you should be able to get an idea of what it looks like.

The last method is browse. The only distinct feature that separates it from all methods above is the fact that it requires authentication.

The implementation looks like this:

public static void Browse(string apiKey, string authToken, string signature, HelperDelegate helperDelegate, string catID = "")
{
    helperDelegateInstance = helperDelegate;

    WebClient client = new WebClient();
    client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
    string URL = string.Format("http://www.flickr.com/services/rest/?method=flickr.groups.browse&api_key={0}&format=json&auth_token={1}&api_sig={2}",
            apiKey, authToken,signature);

    if (catID != "")
        URL += "&cat_id=" + catID;

    client.DownloadStringAsync(new Uri(URL));
}

The main problem with this method is – it seems like there is an error on the Flickr side, so it never returns the correct result and does not accept a correct category ID. Now, you might ask – why would I implement it if it doesn’t work? Well, eventually I hope that it will be fixed. I contacted Flickr support about this issue and will see what the result will be – it is indeed a useful feature to have inside a mobile application.

You can test the response (a JSON response is still received) just like this:

Core.Authentication.GetSignature(param, "SECRET", () =>
{
    Core.Groups.Browse(apiKey, "TOKEN", Core.Authentication.Signature,
    () =>
    {
        Debug.WriteLine(Core.Groups.LastGroupResult);
    },"80");
});

NOTE: The hashing service should be running while this method is called.

80 is the category ID and obviously for now it doesn’t return anything. According to the Flickr documentation, the category ID is set to 0 by default is this parameter is not passed. Following this statement, I am thinking that category IDs are numerical values, but I can’t find any reference to this on Flickr itself.

So far, this is the base class for groups. In the next article, I will show how to retrieve the member list of a specific groups and how to use group pools.

For now, you can download Groups.cs and add it to your Core folder in the existing solution.