Question

I'm sending a bundle of cards to Glass with the Mirror API (c# library)

I know that you can use the default delete menu item on single cards, but is there a way to provide delete functionality for an entire bundle, ideally the result of one action by the users?

I have successfully used the DELETE action on a menu item with the code below

MenuItem mi = new MenuItem();
mi.Action = "DELETE";

TimelineItem tli = new TimelineItem()
{
    Html = itemHtml.ToString(),
    Notification = new NotificationConfig() { Level = "DEFAULT" },
    MenuItems = new List<MenuItem>() { mi }
};

Is there a way to add this delete menu item to a bundle cover? I know this may be tricky because clicking the bundle cover causes you to navigate into the child cards thus no menu is present like on single cards. I'm looking for something (which I did try but it just ignored the menu item) like this:

MenuItem mi = new MenuItem();
mi.Action = "DELETE";

TimelineItem tli = new TimelineItem()
{
    Html = itemHtml.ToString(),
    Notification = new NotificationConfig() { Level = "DEFAULT" },
    IsBundleCover = true,
    BundleId = bundleId,
    MenuItems = new List<MenuItem>() { mi }
};

If not possible on a cover card, is there a way to do this for a bundle by adding delete menu items to the child cards?

Any suggestions would be appreciated

Was it helpful?

Solution

You can use customized menu to do this. The code below is using Java but C# should be similar:

  1. Add customized menu item to the card:

    List<MenuValue> menuValueList = new ArrayList<MenuValue>();
    menuValueList.add(new MenuValue().setIconUrl(iconUrl).setDisplayName("Delete All"));
    
    MenuItem menuItem = new MenuItem();
    menuItem.setValues(menuValueList).setId("delete_bundle_A").setAction("CUSTOM");
    
    List<MenuItem> menuItemList = new ArrayList<MenuItem>();
    menuItemList.add(menuItem);
    
    timelineItem.setMenuItems(menuItemList);
    
  2. Define the controller which handles the callback request of Mirror server notification:

    if (notification.getCollection().equals("timeline") && notification.getUserActions().contains(new UserAction().setType("CUSTOM").setPayload("delete_bundle_A"))) {
        deleteCards(credential, bundleId);
    }
    
  3. The delete card function:

    // if bundleId is null or "", delete all cards
    public static void deleteCards(Credential credential, String bundleId) throws IOException {
        if (bundleId == null) {
            bundleId = "";
        }
        Mirror.Timeline timelineItems = MirrorClient.getMirror(credential).timeline();
        Mirror.Timeline.List list = timelineItems.list();
        List<TimelineItem> timelineItemList = null;
        do {
            TimelineListResponse response = list.execute();
            timelineItemList = response.getItems();
            if (timelineItemList != null && timelineItemList.size() > 0) {
                for (TimelineItem item : timelineItemList) {
                    if (bundleId == "" || bundleId.equalsIgnoreCase(item.getBundleId())) {
                        LOG.info("Deleting card " + item.getId());
                        MirrorClient.deleteTimelineItem(credential, item.getId());
                    }
                }
                list.setPageToken(response.getNextPageToken());
            } else {
                break;
            }
        } while (list.getPageToken() != null && list.getPageToken().length() > 0);
    }
    
  4. Finally, don't forget to subscribe timeline notification when application starts up:

    String notifyUrl = "https://mirrornotifications.appspot.com/forward?url=" + "http://yourServer.com/notify";
    Subscription subscription = MirrorClient.insertSubscription(credential, notifyUrl, userId, "timeline");
    

OTHER TIPS

It isn't clear if you're asking how to create the menu items to delete the entire bundle at once, or if you're looking for code to do the actual delete.

Yuan provides some very good answers to both (not least of which because he actually provides code, which I won't), but there are three things you might also want to consider.

1) You can't have a menu on the bundle cover, but if you don't explicitly specify a bundle cover, then the most recent card will be shown as the cover and will also be shown as the first card in the bundle. You'd be able to get to the menu this way. (The default messaging app works this way, for example, but the first card has the same menu as the rest.)

2) You don't need to create a new menu item. You can leverage the DELETE menu item, if you wish. You'll get a delete notification for one of the cards in the bundle and you can then read the bundleId and delete the rest.

3) You don't need to loop through all the cards you've inserted just to find ones that have that bundleId. That is horribly inefficient. I am not fluent in C#, but from reading the documentation at https://developers.google.com/resources/api-libraries/documentation/mirror/v1/csharp/latest/classGoogle_1_1Apis_1_1Mirror_1_1v1_1_1TimelineResource_1_1ListRequest.html, I get the sense that you can create a ListRequest and then set the bundleId before executing the query and get the results.

So I think you can change Yuan's code to something like:

Mirror.Timeline.List list = timelineItems.list();
list.BundleId = bundleId;
List<TimelineItem> timelineItemList = null;
do {
    TimelineListResponse response = list.execute();
    timelineItemList = response.getItems();
    if (timelineItemList != null && timelineItemList.size() > 0) {
        for (TimelineItem item : timelineItemList) {
            LOG.info("Deleting card " + item.getId());
            MirrorClient.deleteTimelineItem(credential, item.getId());
        }
        list.setPageToken(response.getNextPageToken());
    } else {
        break;
    }
} while (list.getPageToken() != null && list.getPageToken().length() > 0);

(this should be treated as pseudo-code, at best)

If you're confident how many items you've put into a bundle, you might also be able to just set list.MaxResults and not have to iterate over the pages of results. So perhaps something more like

Mirror.Timeline.List list = timelineItems.list();
list.BundleId = bundleId;
list.MaxResults = 20;  // Set to more than the max number of items in a bundle
TimelineListResponse response = list.execute();
List<TimelineItem> timelineItemList = response.getItems();
if (timelineItemList != null && timelineItemList.size() > 0) {
    for (TimelineItem item : timelineItemList) {
        LOG.info("Deleting card " + item.getId());
        MirrorClient.deleteTimelineItem(credential, item.getId());
    }
}

There doesn't appear to be a way to delete a bundle in one step but it's still possible... You can do a GET on /Timeline to get a list of items your app has pushed to the users timeline. Filter that out to find the entries with the bundleId you want to delete. For each of those items, call DELETE /Timeline/{itemid}

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top