Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TIMOB-23828] (5_5_X) iOS 10: Expose the CSSearchQuery API #8281

Merged
merged 8 commits into from
Aug 29, 2016
153 changes: 153 additions & 0 deletions apidoc/Titanium/App/iOS/SearchQuery.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
---
name: Titanium.App.iOS.SearchQuery
summary: |
A search query object manages the criteria to apply when searching app content that you have previously
indexed by using the Core Spotlight APIs.
description: |
You can use this API to search multiple <Titanium.App.iOS.SearchableItem> objects at the same time. You can do that
by using the `queryString` parameter that has a special syntax to filter and index several items. Please refer
to the official [Apple documentation](https://developer.apple.com/reference/corespotlight/cssearchquery) for detailed information on how to structure your search-query to get the
best possible results.

To use this feature make sure you have a compatible device running iOS 10 or later.

To create a SearchableItem object, use the Titanium.App.iOS.createSearchableItem method.
Pass a dictionary of properties to the method that will help identify the item.
At minimum, you must set the [attributeSet](Titanium.App.iOS.SearchableItem.attributeSet) property, which associates
the metadata with the SearchableItem object.
extends: Titanium.Proxy
platforms: [iphone,ipad]
osver: {ios: {min: "10.0"}}
since: "5.5.0"
createable: true

properties:
- name: queryString
summary: A formatted string that defines the matching criteria to apply to indexed items.
description: This parameter cannot be null.
type: String
availability: creation
osver: {ios: {min: "10.0"}}
accessors: false

- name: attributes
summary: An array of strings that represent the attributes of indexed items.
description: |
Each string corresponds to a property name that can be set for an item. For a list of possible properties, see
the <Titanium.App.iOS.SearchableItemAttributeSet> API. Passing null for this parameter means that the query does not use
attributes to find matching items.
type: Array<String>
osver: {ios: {min: "10.0"}}
accessors: false

methods:
- name: start
summary: Asynchronously queries the index for items that match the query object's specifications.

- name: cancel
summary: Cancels a query operation.

- name: isCancelled
summary: A Boolean value that indicates if the query has been cancelled (`true`) or not (`false`).
returns:
type: Boolean
summary: Returns `true` if the query was cancelled.

events:
- name: founditems
summary: Fired when the query finds a new batch of matching items.
properties:
- name: items
summary: An array of indexed items that match the specified query.
type: Array<Titanium.App.iOS.SearchableItem>
- name: foundItemsCount
summary: The number of items that are currently fetched.
type: Number

- name: completed
summary: |
Fired when the query completes to inform you about it's success.
To receive items, use the `founditems` event.
properties:
- name: success
summary: Indicates if the operation succeeded. Returns true if download succeeded, false otherwise.
type: Boolean
- name: error
summary: Error message, if any returned. Undefined otherwise.
type: String

examples:
- title: Perform a simple search-query for all items that start with "Searchable" in it.
example: |
var win = Ti.UI.createWindow({
backgroundColor: "#fff"
});
var btn = Ti.UI.createButton({
title: "Start search-query"
});

var searchItems = [];
var itemAttr = Ti.App.iOS.createSearchableItemAttributeSet({
itemContentType: Ti.App.iOS.UTTYPE_IMAGE,
title: "Titanium Core Spotlight Tutorial"
});

itemAttr.contentDescription = "Tech Example \nOn: " + String.formatDate(new Date(), "short");
itemAttr.keywords = ["Mobile", "Appcelerator", "Titanium"];
itemAttr.displayName = "Hello world";

var item = Ti.App.iOS.createSearchableItem({
uniqueIdentifier: "my-id",
domainIdentifier: "com.mydomain",
attributeSet: itemAttr
});
searchItems.push(item);

var indexer = Ti.App.iOS.createSearchableIndex();

indexer.addToDefaultSearchableIndex(searchItems, function(e) {
if (e.success) {
Ti.API.info("Press the home button and now search for your keywords");
} else {
alert("Searchable index could not be created: " + JSON.stringify(e.error));
}
});

btn.addEventListener("click", function() {
// An array of found Ti.App.iOS.SearchableItem's
var allItems = [];

// The search-query
var searchQuery = Ti.App.iOS.createSearchQuery({
queryString: 'title == "Titanium*"',
attributes: ["title", "displayName", "keywords", "contentType"]
});

// The event to be called when a new batch of items is found
searchQuery.addEventListener("founditems", function(e) {
for (var i = 0; i < e.items.length; i++) {
allItems.push(e.items[i]);
}
});

// The event to be called when the search-query completes
searchQuery.addEventListener("completed", function(e) {
if (!e.success) {
alert(e.error);
}

for (var i = 0; i < allItems.length; i++) {
var attributeSet = allItems[i].attributeSet
var foundTitle = attributeSet.title
var foundDisplayName = attributeSet.displayName

Ti.API.info("title: " + foundTitle + ", displayName: " + foundDisplayName);
}
});

// Start the search-query (or use searchQuery.cancel()) to abort it
searchQuery.start();
});

win.add(btn);
win.open();
2 changes: 1 addition & 1 deletion apidoc/Titanium/UI/ScrollView.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,9 @@ events:
- name: contentSize
summary: |
The current content size of the scroll view defined by its `width` and `height` properties.
Available in Titanium SDK 5.2.0 and later.
type: Dictionary
platforms: [iphone, ipad]
since: "5.2.0"

- name: decelerating
summary: Indicates whether the scroll is decelerating.
Expand Down
2 changes: 1 addition & 1 deletion apidoc/Titanium/UI/TableView.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1210,7 +1210,7 @@ properties:

- name: data
summary: Rows of the table view.
type: [ Dictionary, Array<Titanium.UI.TableViewRow>, Array<Titanium.UI.TableViewSection> ]
type: [Array<Titanium.UI.TableViewRow>, Array<Titanium.UI.TableViewSection>]

- name: editable
summary: |
Expand Down
19 changes: 12 additions & 7 deletions apidoc/Titanium/UI/Window.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1206,7 +1206,7 @@ description: |
</Window>
</Alloy>

`app/controllers/index.xml`:
`app/controllers/index.js`:

var foo = require('foo');
foo.setData({foobar: 42});
Expand Down Expand Up @@ -1308,17 +1308,22 @@ description: |

The example below is a modal window using the Form sheet style:

![modal](http://img.skitch.com/20100406-bqb3f8pb6e4ger7wkcdcw5mbar.png)
<img src="images/window/window-modal.png" width="400" />

You can create this type of modal window on iPad with the following code snippet:

var window = Titanium.UI.createWindow();
window.open({
modal:true,
modalTransitionStyle: Ti.UI.iPhone.MODAL_TRANSITION_STYLE_FLIP_HORIZONTAL,
modalStyle: Ti.UI.iPhone.MODAL_PRESENTATION_FORMSHEET
var win = Ti.UI.iOS.createNavigationWindow({
window: Ti.UI.createWindow({
title: "Modal Window"
})
});

win.open({
modal: true,
modalTransitionStyle: Ti.UI.iOS.MODAL_TRANSITION_STYLE_FLIP_HORIZONTAL,
modalStyle: Ti.UI.iOS.MODAL_PRESENTATION_FORMSHEET
});

#### Mobile Web Behavior

On Mobile Web, windows are always modal, blocking input to underlying
Expand Down
37 changes: 31 additions & 6 deletions iphone/Classes/TiAppiOSProxy.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@
#import "TiAppiOSSearchableItemProxy.h"
#import "TiAppiOSSearchableIndexProxy.h"

#if IS_XCODE_8
#ifdef USE_TI_APPIOSSEARCHQUERY
#import "TiAppiOSSearchQueryProxy.h"
#endif
#endif

#import <MobileCoreServices/MobileCoreServices.h>
#import <CoreLocation/CLCircularRegion.h>

Expand Down Expand Up @@ -190,8 +196,7 @@ -(id)createSearchableIndex:(id)unused
return nil;
}

TiAppiOSSearchableIndexProxy *proxy = [[[TiAppiOSSearchableIndexProxy alloc]init] autorelease];
return proxy;
return [[[TiAppiOSSearchableIndexProxy alloc]init] autorelease];;
}
#endif

Expand All @@ -218,10 +223,9 @@ -(id)createSearchableItem:(id)args
TiAppiOSSearchableItemAttributeSetProxy *attributeSet = nil;
ENSURE_ARG_FOR_KEY(attributeSet, args, @"attributeSet", TiAppiOSSearchableItemAttributeSetProxy);

TiAppiOSSearchableItemProxy *proxy = [[[TiAppiOSSearchableItemProxy alloc]
initWithUniqueIdentifier:uniqueIdentifier
withDomainIdentifier:domainIdentifier
withAttributeSet:attributeSet.attributes] autorelease];
TiAppiOSSearchableItemProxy *proxy = [[[TiAppiOSSearchableItemProxy alloc] initWithUniqueIdentifier:uniqueIdentifier
withDomainIdentifier:domainIdentifier
withAttributeSet:attributeSet.attributes] autorelease];
return proxy;
}
#endif
Expand Down Expand Up @@ -250,6 +254,27 @@ -(id)createSearchableItemAttributeSet:(id)args
}
#endif

#if IS_XCODE_8
#ifdef USE_TI_APPIOSSEARCHQUERY
-(id)createSearchQuery:(id)args
{
if (![TiUtils isIOS10OrGreater]) {
NSLog(@"[ERROR] Search-Queries are only available in iOS 10 and later.");
return nil;
}
if (![NSThread isMainThread]) {
__block id result;
TiThreadPerformOnMainThread(^{result = [[self createSearchQuery:args] retain];}, YES);
return [result autorelease];
}

ENSURE_SINGLE_ARG(args, NSDictionary);

return [[[TiAppiOSSearchQueryProxy alloc] _initWithPageContext:[self pageContext] andArguments:args] autorelease];
}
#endif
#endif

#ifdef USE_TI_APPIOSUSERACTIVITY
-(id)createUserActivity:(id)args
{
Expand Down
30 changes: 30 additions & 0 deletions iphone/Classes/TiAppiOSSearchQueryProxy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* Appcelerator Titanium Mobile
* Copyright (c) 2009-2016 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Apache Public License
* Please see the LICENSE included with this distribution for details.
*/
#if IS_XCODE_8
#ifdef USE_TI_APPIOSSEARCHQUERY
#import "TiProxy.h"
#import <CoreSpotlight/CoreSpotlight.h>

@interface TiAppiOSSearchQueryProxy : TiProxy {
CSSearchQuery *query;
NSString *queryString;
NSArray<NSString*> *attributes;
}

- (id)_initWithPageContext:(id<TiEvaluator>)context andArguments:(NSDictionary*)args;

- (CSSearchQuery*)query;

- (void)start:(id)unused;

- (void)cancel:(id)unused;

- (NSNumber*)isCancelled:(id)unused;

@end
#endif
#endif