Merge remote-tracking branch 'upstream/master'

This commit is contained in:
ojiikun 2013-11-02 21:15:12 +00:00
commit 1748ac6b0d
250 changed files with 9159 additions and 67984 deletions

View file

@ -57,11 +57,15 @@ class Profile(models.Model):
return "%s <%s> (Premium: %s)" % (self.user, self.user.email, self.is_premium) return "%s <%s> (Premium: %s)" % (self.user, self.user.email, self.is_premium)
@property @property
def unread_cutoff(self): def unread_cutoff(self, force_premium=False):
if self.is_premium: if self.is_premium or force_premium:
return datetime.datetime.utcnow() - datetime.timedelta(days=settings.DAYS_OF_UNREAD) return datetime.datetime.utcnow() - datetime.timedelta(days=settings.DAYS_OF_UNREAD)
return datetime.datetime.utcnow() - datetime.timedelta(days=settings.DAYS_OF_UNREAD_FREE) return datetime.datetime.utcnow() - datetime.timedelta(days=settings.DAYS_OF_UNREAD_FREE)
@property
def unread_cutoff_premium(self):
return datetime.datetime.utcnow() - datetime.timedelta(days=settings.DAYS_OF_UNREAD)
def canonical(self): def canonical(self):
return { return {

View file

@ -470,7 +470,8 @@ class UserSubscription(models.Model):
if cutoff_date: if cutoff_date:
cutoff_date = cutoff_date + datetime.timedelta(seconds=1) cutoff_date = cutoff_date + datetime.timedelta(seconds=1)
else: else:
latest_story = MStory.objects(story_feed_id=self.feed.pk).order_by('-story_date').only('story_date').limit(1) latest_story = MStory.objects(story_feed_id=self.feed.pk)\
.order_by('-story_date').only('story_date').limit(1)
if latest_story and len(latest_story) >= 1: if latest_story and len(latest_story) >= 1:
cutoff_date = (latest_story[0]['story_date'] cutoff_date = (latest_story[0]['story_date']
+ datetime.timedelta(seconds=1)) + datetime.timedelta(seconds=1))
@ -548,6 +549,7 @@ class UserSubscription(models.Model):
stories = cache.get('S:%s' % self.feed_id) stories = cache.get('S:%s' % self.feed_id)
unread_story_hashes = self.story_hashes(user_id=self.user_id, feed_ids=[self.feed_id], unread_story_hashes = self.story_hashes(user_id=self.user_id, feed_ids=[self.feed_id],
usersubs=[self],
read_filter='unread', group_by_feed=False, read_filter='unread', group_by_feed=False,
cutoff_date=self.user.profile.unread_cutoff) cutoff_date=self.user.profile.unread_cutoff)
@ -607,6 +609,7 @@ class UserSubscription(models.Model):
feed_scores['neutral'] += 1 feed_scores['neutral'] += 1
else: else:
unread_story_hashes = self.story_hashes(user_id=self.user_id, feed_ids=[self.feed_id], unread_story_hashes = self.story_hashes(user_id=self.user_id, feed_ids=[self.feed_id],
usersubs=[self],
read_filter='unread', group_by_feed=False, read_filter='unread', group_by_feed=False,
include_timestamps=True, include_timestamps=True,
cutoff_date=self.user.profile.unread_cutoff) cutoff_date=self.user.profile.unread_cutoff)

View file

@ -172,7 +172,7 @@ def signup(request):
url = "https://%s%s" % (Site.objects.get_current().domain, url = "https://%s%s" % (Site.objects.get_current().domain,
reverse('stripe-form')) reverse('stripe-form'))
return HttpResponseRedirect(url) return HttpResponseRedirect(url)
return index(request) return index(request)
@never_cache @never_cache
@ -607,7 +607,7 @@ def load_single_feed(request, feed_id):
if not include_story_content: if not include_story_content:
del story['story_content'] del story['story_content']
story_date = localtime_for_timezone(story['story_date'], user.profile.timezone) story_date = localtime_for_timezone(story['story_date'], user.profile.timezone)
story['short_parsed_date'] = format_story_link_date__short(story_date, now) story['short_parsed_date'] = format_story_link_date__short(story_date)
story['long_parsed_date'] = format_story_link_date__long(story_date, now) story['long_parsed_date'] = format_story_link_date__long(story_date, now)
if usersub: if usersub:
story['read_status'] = 1 story['read_status'] = 1
@ -677,9 +677,10 @@ def load_single_feed(request, feed_id):
# if page <= 1: # if page <= 1:
# import random # import random
# if random.random() < .5:
# assert False
# time.sleep(random.randint(0, 3)) # time.sleep(random.randint(0, 3))
# if page == 2:
# assert False
return data return data
@ -783,7 +784,7 @@ def load_starred_stories(request):
for story in stories: for story in stories:
story_date = localtime_for_timezone(story['story_date'], user.profile.timezone) story_date = localtime_for_timezone(story['story_date'], user.profile.timezone)
story['short_parsed_date'] = format_story_link_date__short(story_date, now) story['short_parsed_date'] = format_story_link_date__short(story_date)
story['long_parsed_date'] = format_story_link_date__long(story_date, now) story['long_parsed_date'] = format_story_link_date__long(story_date, now)
starred_date = localtime_for_timezone(story['starred_date'], user.profile.timezone) starred_date = localtime_for_timezone(story['starred_date'], user.profile.timezone)
story['starred_date'] = format_story_link_date__long(starred_date, now) story['starred_date'] = format_story_link_date__long(starred_date, now)
@ -945,7 +946,7 @@ def load_river_stories__redis(request):
story['story_hash'] not in unread_feed_story_hashes): story['story_hash'] not in unread_feed_story_hashes):
story['read_status'] = 1 story['read_status'] = 1
story_date = localtime_for_timezone(story['story_date'], user.profile.timezone) story_date = localtime_for_timezone(story['story_date'], user.profile.timezone)
story['short_parsed_date'] = format_story_link_date__short(story_date, now) story['short_parsed_date'] = format_story_link_date__short(story_date)
story['long_parsed_date'] = format_story_link_date__long(story_date, now) story['long_parsed_date'] = format_story_link_date__long(story_date, now)
if story['story_hash'] in starred_stories: if story['story_hash'] in starred_stories:
story['starred'] = True story['starred'] = True
@ -1256,9 +1257,16 @@ def mark_story_as_unread(request):
if story.story_date < request.user.profile.unread_cutoff: if story.story_date < request.user.profile.unread_cutoff:
data['code'] = -1 data['code'] = -1
data['message'] = "Story is more than %s days old, cannot mark as unread." % ( if request.user.profile.is_premium:
settings.DAYS_OF_UNREAD if request.user.profile.is_premium else data['message'] = "Story is more than %s days old, cannot mark as unread." % (
settings.DAYS_OF_UNREAD_FREE) settings.DAYS_OF_UNREAD)
elif story.story_date > request.user.profile.unread_cutoff_premium:
data['message'] = "Story is more than %s days old. Premiums can mark unread up to 30 days." % (
settings.DAYS_OF_UNREAD_FREE)
else:
data['message'] = "Story is more than %s days old, cannot mark as unread." % (
settings.DAYS_OF_UNREAD_FREE)
return data
social_subs = MSocialSubscription.mark_dirty_sharing_story(user_id=request.user.pk, social_subs = MSocialSubscription.mark_dirty_sharing_story(user_id=request.user.pk,
story_feed_id=feed_id, story_feed_id=feed_id,

View file

@ -431,7 +431,7 @@ def original_text(request):
story_id = request.REQUEST.get('story_id') story_id = request.REQUEST.get('story_id')
feed_id = request.REQUEST.get('feed_id') feed_id = request.REQUEST.get('feed_id')
force = request.REQUEST.get('force', False) force = request.REQUEST.get('force', False)
story, _ = MStory.find_story(story_id=story_id, story_feed_id=feed_id) story, _ = MStory.find_story(story_id=story_id, story_feed_id=feed_id)
if not story: if not story:

View file

@ -1911,18 +1911,22 @@ class MSharedStory(mongo.Document):
self.guid_hash[:6] self.guid_hash[:6]
) )
def generate_post_to_service_message(self, include_url=True): def generate_post_to_service_message(self, truncate=None, include_url=True):
message = strip_tags(self.comments) message = strip_tags(self.comments)
if not message or len(message) < 1: if not message or len(message) < 1:
message = self.story_title message = self.story_title
if include_url: if include_url and truncate:
message = truncate_chars(message, 92) message = truncate_chars(message, truncate - 18 - 30)
feed = Feed.get_by_id(self.story_feed_id) feed = Feed.get_by_id(self.story_feed_id)
message += " (%s)" % truncate_chars(feed.feed_title, 18) if truncate:
message += " (%s)" % truncate_chars(feed.feed_title, 18)
else:
message += " (%s)" % truncate_chars(feed.feed_title, 30)
if include_url: if include_url:
message += " " + self.blurblog_permalink() message += " " + self.blurblog_permalink()
elif include_url: elif include_url:
message = truncate_chars(message, 116) if truncate:
message = truncate_chars(message, truncate - 14)
message += " " + self.blurblog_permalink() message += " " + self.blurblog_permalink()
return message return message
@ -2521,7 +2525,7 @@ class MSocialServices(mongo.Document):
return profile return profile
def post_to_twitter(self, shared_story): def post_to_twitter(self, shared_story):
message = shared_story.generate_post_to_service_message() message = shared_story.generate_post_to_service_message(truncate=140)
try: try:
api = self.twitter_api() api = self.twitter_api()
@ -2555,7 +2559,7 @@ class MSocialServices(mongo.Document):
return True return True
def post_to_appdotnet(self, shared_story): def post_to_appdotnet(self, shared_story):
message = shared_story.generate_post_to_service_message() message = shared_story.generate_post_to_service_message(truncate=256)
try: try:
api = self.appdotnet_api() api = self.appdotnet_api()

View file

@ -123,8 +123,8 @@ def load_social_stories(request, user_id, username=None):
story['social_user_id'] = social_user_id story['social_user_id'] = social_user_id
# story_date = localtime_for_timezone(story['story_date'], user.profile.timezone) # story_date = localtime_for_timezone(story['story_date'], user.profile.timezone)
shared_date = localtime_for_timezone(story['shared_date'], user.profile.timezone) shared_date = localtime_for_timezone(story['shared_date'], user.profile.timezone)
story['short_parsed_date'] = format_story_link_date__short(shared_date, now) story['short_parsed_date'] = format_story_link_date__short(shared_date)
story['long_parsed_date'] = format_story_link_date__long(shared_date, now) story['long_parsed_date'] = format_story_link_date__long(shared_date)
story['read_status'] = 1 story['read_status'] = 1
if (read_filter == 'all' or query) and socialsub: if (read_filter == 'all' or query) and socialsub:
@ -275,7 +275,7 @@ def load_river_blurblog(request):
if story['story_hash'] not in unread_feed_story_hashes: if story['story_hash'] not in unread_feed_story_hashes:
story['read_status'] = 1 story['read_status'] = 1
story_date = localtime_for_timezone(story['story_date'], user.profile.timezone) story_date = localtime_for_timezone(story['story_date'], user.profile.timezone)
story['short_parsed_date'] = format_story_link_date__short(story_date, now) story['short_parsed_date'] = format_story_link_date__short(story_date)
story['long_parsed_date'] = format_story_link_date__long(story_date, now) story['long_parsed_date'] = format_story_link_date__long(story_date, now)
if story['story_hash'] in starred_stories: if story['story_hash'] in starred_stories:
story['starred'] = True story['starred'] = True

View file

@ -1,6 +1,7 @@
package com.newsblur.activity; package com.newsblur.activity;
import com.actionbarsherlock.app.SherlockPreferenceActivity; import com.actionbarsherlock.app.SherlockPreferenceActivity;
import com.actionbarsherlock.view.MenuItem;
import com.newsblur.R; import com.newsblur.R;
import com.newsblur.util.PrefConstants; import com.newsblur.util.PrefConstants;
@ -11,8 +12,19 @@ public class Settings extends SherlockPreferenceActivity {
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
super.getPreferenceManager().setSharedPreferencesName(PrefConstants.PREFERENCES); super.getPreferenceManager().setSharedPreferencesName(PrefConstants.PREFERENCES);
addPreferencesFromResource(R.layout.activity_settings); addPreferencesFromResource(R.layout.activity_settings);
} }
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
} }

565
clients/ios/AFNetworking/AFHTTPClient.h Normal file → Executable file
View file

@ -1,17 +1,17 @@
// AFHTTPClient.h // AFHTTPClient.h
// //
// Copyright (c) 2011 Gowalla (http://gowalla.com/) // Copyright (c) 2011 Gowalla (http://gowalla.com/)
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights // in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is // copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions: // furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -21,25 +21,58 @@
// THE SOFTWARE. // THE SOFTWARE.
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "AFURLConnectionOperation.h"
@class AFHTTPRequestOperation; #import <Availability.h>
@protocol AFHTTPClientOperation;
@protocol AFMultipartFormData;
/** /**
Posted when network reachability changes. `AFHTTPClient` captures the common patterns of communicating with an web application over HTTP. It encapsulates information like base URL, authorization credentials, and HTTP headers, and uses them to construct and manage the execution of HTTP request operations.
The notification object is an `NSNumber` object containing the boolean value for the current network reachability.
This notification contains no information in the `userInfo` dictionary.
@warning In order for network reachability to be monitored, include the `SystemConfiguration` framework in the active target's "Link Binary With Library" build phase, and add `#import <SystemConfiguration/SystemConfiguration.h>` to the header prefix of the project (Prefix.pch).
*/
#ifdef _SYSTEMCONFIGURATION_H
extern NSString * const AFNetworkingReachabilityDidChangeNotification;
#endif
/** ## Automatic Content Parsing
Specifies network reachability of the client to its `baseURL` domain.
Instances of `AFHTTPClient` may specify which types of requests it expects and should handle by registering HTTP operation classes for automatic parsing. Registered classes will determine whether they can handle a particular request, and then construct a request operation accordingly in `enqueueHTTPRequestOperationWithRequest:success:failure`.
## Subclassing Notes
In most cases, one should create an `AFHTTPClient` subclass for each website or web application that your application communicates with. It is often useful, also, to define a class method that returns a singleton shared HTTP client in each subclass, that persists authentication credentials and other configuration across the entire application.
## Methods to Override
To change the behavior of all url request construction for an `AFHTTPClient` subclass, override `requestWithMethod:path:parameters`.
To change the behavior of all request operation construction for an `AFHTTPClient` subclass, override `HTTPRequestOperationWithRequest:success:failure`.
## Default Headers
By default, `AFHTTPClient` sets the following HTTP headers:
- `Accept-Language: (comma-delimited preferred languages), en-us;q=0.8`
- `User-Agent: (generated user agent)`
You can override these HTTP headers or define new ones using `setDefaultHeader:value:`.
## URL Construction Using Relative Paths
Both `-requestWithMethod:path:parameters:` and `-multipartFormRequestWithMethod:path:parameters:constructingBodyWithBlock:` construct URLs from the path relative to the `-baseURL`, using `NSURL +URLWithString:relativeToURL:`. Below are a few examples of how `baseURL` and relative paths interact:
NSURL *baseURL = [NSURL URLWithString:@"http://example.com/v1/"];
[NSURL URLWithString:@"foo" relativeToURL:baseURL]; // http://example.com/v1/foo
[NSURL URLWithString:@"foo?bar=baz" relativeToURL:baseURL]; // http://example.com/v1/foo?bar=baz
[NSURL URLWithString:@"/foo" relativeToURL:baseURL]; // http://example.com/foo
[NSURL URLWithString:@"foo/" relativeToURL:baseURL]; // http://example.com/v1/foo
[NSURL URLWithString:@"/foo/" relativeToURL:baseURL]; // http://example.com/foo/
[NSURL URLWithString:@"http://example2.com/" relativeToURL:baseURL]; // http://example2.com/
Also important to note is that a trailing slash will be added to any `baseURL` without one, which would otherwise cause unexpected behavior when constructing URLs using paths without a leading slash.
## NSCoding / NSCopying Conformance
`AFHTTPClient` conforms to the `NSCoding` and `NSCopying` protocols, allowing operations to be archived to disk, and copied in memory, respectively. There are a few minor caveats to keep in mind, however:
- Archives and copies of HTTP clients will be initialized with an empty operation queue.
- NSCoding cannot serialize / deserialize block properties, so an archive of an HTTP client will not include any reachability callback block that may be set.
*/ */
#ifdef _SYSTEMCONFIGURATION_H #ifdef _SYSTEMCONFIGURATION_H
typedef enum { typedef enum {
AFNetworkReachabilityStatusUnknown = -1, AFNetworkReachabilityStatusUnknown = -1,
@ -47,94 +80,37 @@ typedef enum {
AFNetworkReachabilityStatusReachableViaWWAN = 1, AFNetworkReachabilityStatusReachableViaWWAN = 1,
AFNetworkReachabilityStatusReachableViaWiFi = 2, AFNetworkReachabilityStatusReachableViaWiFi = 2,
} AFNetworkReachabilityStatus; } AFNetworkReachabilityStatus;
#else
#pragma message("SystemConfiguration framework not found in project, or not included in precompiled header. Network reachability functionality will not be available.")
#endif
#ifndef __UTTYPE__
#if __IPHONE_OS_VERSION_MIN_REQUIRED
#pragma message("MobileCoreServices framework not found in project, or not included in precompiled header. Automatic MIME type detection when uploading files in multipart requests will not be available.")
#else
#pragma message("CoreServices framework not found in project, or not included in precompiled header. Automatic MIME type detection when uploading files in multipart requests will not be available.")
#endif
#endif #endif
/**
Specifies the method used to encode parameters into request body.
*/
typedef enum { typedef enum {
AFFormURLParameterEncoding, AFFormURLParameterEncoding,
AFJSONParameterEncoding, AFJSONParameterEncoding,
AFPropertyListParameterEncoding, AFPropertyListParameterEncoding,
} AFHTTPClientParameterEncoding; } AFHTTPClientParameterEncoding;
/** @class AFHTTPRequestOperation;
Returns a string, replacing certain characters with the equivalent percent escape sequence based on the specified encoding. @protocol AFMultipartFormData;
@param string The string to URL encode
@param encoding The encoding to use for the replacement. If you are uncertain of the correct encoding, you should use UTF-8 (NSUTF8StringEncoding), which is the encoding designated by RFC 3986 as the correct encoding for use in URLs.
@discussion The characters escaped are all characters that are not legal URL characters (based on RFC 3986), including any whitespace, punctuation, or special characters.
@return A URL-encoded string. If it does not need to be modified (no percent escape sequences are missing), this function may merely return string argument.
*/
extern NSString * AFURLEncodedStringFromStringWithEncoding(NSString *string, NSStringEncoding encoding);
/** @interface AFHTTPClient : NSObject <NSCoding, NSCopying>
Returns a query string constructed by a set of parameters, using the specified encoding.
@param parameters The parameters used to construct the query string
@param encoding The encoding to use in constructing the query string. If you are uncertain of the correct encoding, you should use UTF-8 (NSUTF8StringEncoding), which is the encoding designated by RFC 3986 as the correct encoding for use in URLs.
@discussion Query strings are constructed by collecting each key-value pair, URL-encoding a string representation of the key-value pair, and then joining the components with "&".
If a key-value pair has a an `NSArray` for its value, each member of the array will be represented in the format `key[]=value1&key[]value2`. Otherwise, the key-value pair will be formatted as "key=value". String representations of both keys and values are derived using the `-description` method. The constructed query string does not include the ? character used to delimit the query component.
@return A URL-encoded query string
*/
extern NSString * AFQueryStringFromParametersWithEncoding(NSDictionary *parameters, NSStringEncoding encoding);
/**
`AFHTTPClient` captures the common patterns of communicating with an web application over HTTP. It encapsulates information like base URL, authorization credentials, and HTTP headers, and uses them to construct and manage the execution of HTTP request operations.
## Automatic Content Parsing
Instances of `AFHTTPClient` may specify which types of requests it expects and should handle by registering HTTP operation classes for automatic parsing. Registered classes will determine whether they can handle a particular request, and then construct a request operation accordingly in `enqueueHTTPRequestOperationWithRequest:success:failure`. See `AFHTTPClientOperation` for further details.
## Subclassing Notes
In most cases, one should create an `AFHTTPClient` subclass for each website or web application that your application communicates with. It is often useful, also, to define a class method that returns a singleton shared HTTP client in each subclass, that persists authentication credentials and other configuration across the entire application.
## Methods to Override
To change the behavior of all url request construction for an `AFHTTPClient` subclass, override `requestWithMethod:path:parameters`.
To change the behavior of all request operation construction for an `AFHTTPClient` subclass, override `HTTPRequestOperationWithRequest:success:failure`.
## Default Headers
By default, `AFHTTPClient` sets the following HTTP headers:
- `Accept-Encoding: gzip`
- `Accept-Language: ([NSLocale preferredLanguages]), en-us;q=0.8`
- `User-Agent: (generated user agent)`
You can override these HTTP headers or define new ones using `setDefaultHeader:value:`.
## URL Construction Using Relative Paths
Both `requestWithMethod:path:parameters` and `multipartFormRequestWithMethod:path:parameters:constructingBodyWithBlock:` construct URLs from the path relative to the `baseURL`, using `NSURL +URLWithString:relativeToURL:`. Below are a few examples of how `baseURL` and relative paths interract:
NSURL *baseURL = [NSURL URLWithString:@"http://example.com/v1/"];
[NSURL URLWithString:@"foo" relativeToURL:baseURL]; // http://example.com/v1/foo
[NSURL URLWithString:@"foo?bar=baz" relativeToURL:baseURL]; // http://example.com/v1/foo?bar=baz
[NSURL URLWithString:@"/foo" relativeToURL:baseURL]; // http://example.com/foo
[NSURL URLWithString:@"foo/" relativeToURL:baseURL]; // http://example.com/v1/foo
[NSURL URLWithString:@"/foo/" relativeToURL:baseURL]; // http://example.com/foo/
[NSURL URLWithString:@"http://example2.com/" relativeToURL:baseURL]; // http://example2.com/
*/
@interface AFHTTPClient : NSObject
///--------------------------------------- ///---------------------------------------
/// @name Accessing HTTP Client Properties /// @name Accessing HTTP Client Properties
///--------------------------------------- ///---------------------------------------
/** /**
The url used as the base for paths specified in methods such as `getPath:parameteres:success:failure` The url used as the base for paths specified in methods such as `getPath:parameters:success:failure`
*/ */
@property (readonly, nonatomic, retain) NSURL *baseURL; @property (readonly, nonatomic, strong) NSURL *baseURL;
/** /**
The string encoding used in constructing url requests. This is `NSUTF8StringEncoding` by default. The string encoding used in constructing url requests. This is `NSUTF8StringEncoding` by default.
@ -144,44 +120,56 @@ extern NSString * AFQueryStringFromParametersWithEncoding(NSDictionary *paramete
/** /**
The `AFHTTPClientParameterEncoding` value corresponding to how parameters are encoded into a request body. This is `AFFormURLParameterEncoding` by default. The `AFHTTPClientParameterEncoding` value corresponding to how parameters are encoded into a request body. This is `AFFormURLParameterEncoding` by default.
@warning JSON encoding will automatically use JSONKit, SBJSON, YAJL, or NextiveJSON, if provided. Otherwise, the built-in `NSJSONSerialization` class is used, if available (iOS 5.0 and Mac OS 10.7). If the build target does not either support `NSJSONSerialization` or include a third-party JSON library, a runtime exception will be thrown when attempting to encode parameters as JSON. @warning Some nested parameter structures, such as a keyed array of hashes containing inconsistent keys (i.e. `@{@"": @[@{@"a" : @(1)}, @{@"b" : @(2)}]}`), cannot be unambiguously represented in query strings. It is strongly recommended that an unambiguous encoding, such as `AFJSONParameterEncoding`, is used when posting complicated or nondeterministic parameter structures.
*/ */
@property (nonatomic, assign) AFHTTPClientParameterEncoding parameterEncoding; @property (nonatomic, assign) AFHTTPClientParameterEncoding parameterEncoding;
/** /**
The operation queue which manages operations enqueued by the HTTP client. The operation queue which manages operations enqueued by the HTTP client.
*/ */
@property (readonly, nonatomic, retain) NSOperationQueue *operationQueue; @property (readonly, nonatomic, strong) NSOperationQueue *operationQueue;
/** /**
The reachability status from the device to the current `baseURL` of the `AFHTTPClient`. The reachability status from the device to the current `baseURL` of the `AFHTTPClient`.
@warning This property requires the `SystemConfiguration` framework. Add it in the active target's "Link Binary With Library" build phase, and add `#import <SystemConfiguration/SystemConfiguration.h>` to the header prefix of the project (Prefix.pch). @warning This property requires the `SystemConfiguration` framework. Add it in the active target's "Link Binary With Library" build phase, and add `#import <SystemConfiguration/SystemConfiguration.h>` to the header prefix of the project (`Prefix.pch`).
*/ */
#ifdef _SYSTEMCONFIGURATION_H #ifdef _SYSTEMCONFIGURATION_H
@property (readonly, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus; @property (readonly, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus;
#endif #endif
/**
Default SSL pinning mode for each `AFHTTPRequestOperation` created by `HTTPRequestOperationWithRequest:success:failure:`.
*/
@property (nonatomic, assign) AFURLConnectionOperationSSLPinningMode defaultSSLPinningMode;
/**
Whether each `AFHTTPRequestOperation` created by `HTTPRequestOperationWithRequest:success:failure:` should accept an invalid SSL certificate.
If `_AFNETWORKING_ALLOW_INVALID_SSL_CERTIFICATES_` is set, this property defaults to `YES` for backwards compatibility. Otherwise, this property defaults to `NO`.
*/
@property (nonatomic, assign) BOOL allowsInvalidSSLCertificate;
///--------------------------------------------- ///---------------------------------------------
/// @name Creating and Initializing HTTP Clients /// @name Creating and Initializing HTTP Clients
///--------------------------------------------- ///---------------------------------------------
/** /**
Creates and initializes an `AFHTTPClient` object with the specified base URL. Creates and initializes an `AFHTTPClient` object with the specified base URL.
@param url The base URL for the HTTP client. This argument must not be nil. @param url The base URL for the HTTP client. This argument must not be `nil`.
@return The newly-initialized HTTP client @return The newly-initialized HTTP client
*/ */
+ (AFHTTPClient *)clientWithBaseURL:(NSURL *)url; + (instancetype)clientWithBaseURL:(NSURL *)url;
/** /**
Initializes an `AFHTTPClient` object with the specified base URL. Initializes an `AFHTTPClient` object with the specified base URL.
@param url The base URL for the HTTP client. This argument must not be nil. This is the designated initializer.
@discussion This is the designated initializer. @param url The base URL for the HTTP client. This argument must not be `nil`.
@return The newly-initialized HTTP client @return The newly-initialized HTTP client
*/ */
- (id)initWithBaseURL:(NSURL *)url; - (id)initWithBaseURL:(NSURL *)url;
@ -192,10 +180,10 @@ extern NSString * AFQueryStringFromParametersWithEncoding(NSDictionary *paramete
/** /**
Sets a callback to be executed when the network availability of the `baseURL` host changes. Sets a callback to be executed when the network availability of the `baseURL` host changes.
@param block A block object to be executed when the network availability of the `baseURL` host changes.. This block has no return value and takes a single argument which represents the various reachability states from the device to the `baseURL`. @param block A block object to be executed when the network availability of the `baseURL` host changes.. This block has no return value and takes a single argument which represents the various reachability states from the device to the `baseURL`.
@warning This method requires the `SystemConfiguration` framework. Add it in the active target's "Link Binary With Library" build phase, and add `#import <SystemConfiguration/SystemConfiguration.h>` to the header prefix of the project (Prefix.pch). @warning This method requires the `SystemConfiguration` framework. Add it in the active target's "Link Binary With Library" build phase, and add `#import <SystemConfiguration/SystemConfiguration.h>` to the header prefix of the project (`Prefix.pch`).
*/ */
#ifdef _SYSTEMCONFIGURATION_H #ifdef _SYSTEMCONFIGURATION_H
- (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block; - (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block;
@ -207,23 +195,19 @@ extern NSString * AFQueryStringFromParametersWithEncoding(NSDictionary *paramete
/** /**
Attempts to register a subclass of `AFHTTPRequestOperation`, adding it to a chain to automatically generate request operations from a URL request. Attempts to register a subclass of `AFHTTPRequestOperation`, adding it to a chain to automatically generate request operations from a URL request.
When `enqueueHTTPRequestOperationWithRequest:success:failure` is invoked, each registered class is consulted in turn to see if it can handle the specific request. The first class to return `YES` when sent a `canProcessRequest:` message is used to create an operation using `initWithURLRequest:` and do `setCompletionBlockWithSuccess:failure:`. There is no guarantee that all registered classes will be consulted. Classes are consulted in the reverse order of their registration. Attempting to register an already-registered class will move it to the top of the list.
@param The subclass of `AFHTTPRequestOperation` to register @param operationClass The subclass of `AFHTTPRequestOperation` to register
@return `YES` if the registration is successful, `NO` otherwise. The only failure condition is if `operationClass` does is not a subclass of `AFHTTPRequestOperation`. @return `YES` if the registration is successful, `NO` otherwise. The only failure condition is if `operationClass` is not a subclass of `AFHTTPRequestOperation`.
@discussion When `enqueueHTTPRequestOperationWithRequest:success:failure` is invoked, each registered class is consulted in turn to see if it can handle the specific request. The first class to return `YES` when sent a `canProcessRequest:` message is used to create an operation using `initWithURLRequest:` and do `setCompletionBlockWithSuccess:failure:`. There is no guarantee that all registered classes will be consulted. Classes are consulted in the reverse order of their registration. Attempting to register an already-registered class will move it to the top of the list.
@see `AFHTTPClientOperation`
*/ */
- (BOOL)registerHTTPOperationClass:(Class)operationClass; - (BOOL)registerHTTPOperationClass:(Class)operationClass;
/** /**
Unregisters the specified subclass of `AFHTTPRequestOperation`. Unregisters the specified subclass of `AFHTTPRequestOperation` from the chain of classes consulted when `-requestWithMethod:path:parameters` is called.
@param The class conforming to the `AFHTTPClientOperation` protocol to unregister @param operationClass The subclass of `AFHTTPRequestOperation` to register
@discussion After this method is invoked, `operationClass` is no longer consulted when `requestWithMethod:path:parameters` is invoked.
*/ */
- (void)unregisterHTTPOperationClass:(Class)operationClass; - (void)unregisterHTTPOperationClass:(Class)operationClass;
@ -233,72 +217,84 @@ extern NSString * AFQueryStringFromParametersWithEncoding(NSDictionary *paramete
/** /**
Returns the value for the HTTP headers set in request objects created by the HTTP client. Returns the value for the HTTP headers set in request objects created by the HTTP client.
@param header The HTTP header to return the default value for @param header The HTTP header to return the default value for
@return The default value for the HTTP header, or `nil` if unspecified @return The default value for the HTTP header, or `nil` if unspecified
*/ */
- (NSString *)defaultValueForHeader:(NSString *)header; - (NSString *)defaultValueForHeader:(NSString *)header;
/** /**
Sets the value for the HTTP headers set in request objects made by the HTTP client. If `nil`, removes the existing value for that header. Sets the value for the HTTP headers set in request objects made by the HTTP client. If `nil`, removes the existing value for that header.
@param header The HTTP header to set a default value for @param header The HTTP header to set a default value for
@param value The value set as default for the specified header, or `nil @param value The value set as default for the specified header, or `nil
*/ */
- (void)setDefaultHeader:(NSString *)header value:(NSString *)value; - (void)setDefaultHeader:(NSString *)header
value:(NSString *)value;
/** /**
Sets the "Authorization" HTTP header set in request objects made by the HTTP client to a basic authentication value with Base64-encoded username and password. This overwrites any existing value for this header. Sets the "Authorization" HTTP header set in request objects made by the HTTP client to a basic authentication value with Base64-encoded username and password. This overwrites any existing value for this header.
@param username The HTTP basic auth username @param username The HTTP basic auth username
@param password The HTTP basic auth password @param password The HTTP basic auth password
*/ */
- (void)setAuthorizationHeaderWithUsername:(NSString *)username password:(NSString *)password; - (void)setAuthorizationHeaderWithUsername:(NSString *)username
password:(NSString *)password;
/** /**
Sets the "Authorization" HTTP header set in request objects made by the HTTP client to a token-based authentication value, such as an OAuth access token. This overwrites any existing value for this header. Sets the "Authorization" HTTP header set in request objects made by the HTTP client to a token-based authentication value, such as an OAuth access token. This overwrites any existing value for this header.
@param token The authentication token @param token The authentication token
*/ */
- (void)setAuthorizationHeaderWithToken:(NSString *)token; - (void)setAuthorizationHeaderWithToken:(NSString *)token;
/** /**
Clears any existing value for the "Authorization" HTTP header. Clears any existing value for the "Authorization" HTTP header.
*/ */
- (void)clearAuthorizationHeader; - (void)clearAuthorizationHeader;
///-------------------------------
/// @name Managing URL Credentials
///-------------------------------
/**
Set the default URL credential to be set for request operations.
@param credential The URL credential
*/
- (void)setDefaultCredential:(NSURLCredential *)credential;
///------------------------------- ///-------------------------------
/// @name Creating Request Objects /// @name Creating Request Objects
///------------------------------- ///-------------------------------
/** /**
Creates an `NSMutableURLRequest` object with the specified HTTP method and path. Creates an `NSMutableURLRequest` object with the specified HTTP method and path.
If the HTTP method is `GET`, the parameters will be used to construct a url-encoded query string that is appended to the request's URL. Otherwise, the parameters will be encoded according to the value of the `parameterEncoding` property, and set as the request body. If the HTTP method is `GET`, `HEAD`, or `DELETE`, the parameters will be used to construct a url-encoded query string that is appended to the request's URL. Otherwise, the parameters will be encoded according to the value of the `parameterEncoding` property, and set as the request body.
@param method The HTTP method for the request, such as `GET`, `POST`, `PUT`, or `DELETE`. @param method The HTTP method for the request, such as `GET`, `POST`, `PUT`, or `DELETE`. This parameter must not be `nil`.
@param path The path to be appended to the HTTP client's base URL and used as the request URL. @param path The path to be appended to the HTTP client's base URL and used as the request URL. If `nil`, no path will be appended to the base URL.
@param parameters The parameters to be either set as a query string for `GET` requests, or the request HTTP body. @param parameters The parameters to be either set as a query string for `GET` requests, or the request HTTP body.
@return An `NSMutableURLRequest` object @return An `NSMutableURLRequest` object
*/ */
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method - (NSMutableURLRequest *)requestWithMethod:(NSString *)method
path:(NSString *)path path:(NSString *)path
parameters:(NSDictionary *)parameters; parameters:(NSDictionary *)parameters;
/** /**
Creates an `NSMutableURLRequest` object with the specified HTTP method and path, and constructs a `multipart/form-data` HTTP body, using the specified parameters and multipart form data block. See http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.2 Creates an `NSMutableURLRequest` object with the specified HTTP method and path, and constructs a `multipart/form-data` HTTP body, using the specified parameters and multipart form data block. See http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.2
Multipart form requests are automatically streamed, reading files directly from disk along with in-memory data in a single HTTP body. The resulting `NSMutableURLRequest` object has an `HTTPBodyStream` property, so refrain from setting `HTTPBodyStream` or `HTTPBody` on this request object, as it will clear out the multipart form body stream.
@param method The HTTP method for the request. Must be either `POST`, `PUT`, or `DELETE`. @param method The HTTP method for the request. This parameter must not be `GET` or `HEAD`, or `nil`.
@param path The path to be appended to the HTTP client's base URL and used as the request URL. @param path The path to be appended to the HTTP client's base URL and used as the request URL.
@param parameters The parameters to be encoded and set in the request HTTP body. @param parameters The parameters to be encoded and set in the request HTTP body.
@param block A block that takes a single argument and appends data to the HTTP body. The block argument is an object adopting the `AFMultipartFormData` protocol. This can be used to upload files, encode HTTP body as JSON or XML, or specify multiple values for the same parameter, as one might for array values. @param block A block that takes a single argument and appends data to the HTTP body. The block argument is an object adopting the `AFMultipartFormData` protocol. This can be used to upload files, encode HTTP body as JSON or XML, or specify multiple values for the same parameter, as one might for array values.
@discussion The multipart form data is constructed synchronously in the specified block, so in cases where large amounts of data are being added to the request, you should consider performing this method in the background. Likewise, the form data is constructed in-memory, so it may be advantageous to instead write parts of the form data to a file and stream the request body using the `HTTPBodyStream` property of `NSURLRequest`.
@warning An exception will be raised if the specified method is not `POST`, `PUT` or `DELETE`.
@return An `NSMutableURLRequest` object @return An `NSMutableURLRequest` object
*/ */
- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method - (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method
@ -312,14 +308,14 @@ extern NSString * AFQueryStringFromParametersWithEncoding(NSDictionary *paramete
/** /**
Creates an `AFHTTPRequestOperation`. Creates an `AFHTTPRequestOperation`.
In order to determine what kind of operation is created, each registered subclass conforming to the `AFHTTPClient` protocol is consulted (in reverse order of when they were specified) to see if it can handle the specific request. The first class to return `YES` when sent a `canProcessRequest:` message is used to generate an operation using `HTTPRequestOperationWithRequest:success:failure:`. In order to determine what kind of operation is created, each registered subclass conforming to the `AFHTTPClient` protocol is consulted (in reverse order of when they were specified) to see if it can handle the specific request. The first class to return `YES` when sent a `canProcessRequest:` message is used to generate an operation using `HTTPRequestOperationWithRequest:success:failure:`.
@param request The request object to be loaded asynchronously during execution of the operation. @param urlRequest The request object to be loaded asynchronously during execution of the operation.
@param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request. @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request.
@param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred.
*/ */
- (AFHTTPRequestOperation *)HTTPRequestOperationWithRequest:(NSURLRequest *)request - (AFHTTPRequestOperation *)HTTPRequestOperationWithRequest:(NSURLRequest *)urlRequest
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure;
@ -329,7 +325,7 @@ extern NSString * AFQueryStringFromParametersWithEncoding(NSDictionary *paramete
/** /**
Enqueues an `AFHTTPRequestOperation` to the HTTP client's operation queue. Enqueues an `AFHTTPRequestOperation` to the HTTP client's operation queue.
@param operation The HTTP request operation to be enqueued. @param operation The HTTP request operation to be enqueued.
*/ */
- (void)enqueueHTTPRequestOperation:(AFHTTPRequestOperation *)operation; - (void)enqueueHTTPRequestOperation:(AFHTTPRequestOperation *)operation;
@ -337,8 +333,10 @@ extern NSString * AFQueryStringFromParametersWithEncoding(NSDictionary *paramete
/** /**
Cancels all operations in the HTTP client's operation queue whose URLs match the specified HTTP method and path. Cancels all operations in the HTTP client's operation queue whose URLs match the specified HTTP method and path.
@param method The HTTP method to match for the cancelled requests, such as `GET`, `POST`, `PUT`, or `DELETE`. If `nil`, all request operations with URLs matching the path will be cancelled. This method only cancels `AFHTTPRequestOperations` whose request URL matches the HTTP client base URL with the path appended. For complete control over the lifecycle of enqueued operations, you can access the `operationQueue` property directly, which allows you to, for instance, cancel operations filtered by a predicate, or simply use `-cancelAllRequests`. Note that the operation queue may include non-HTTP operations, so be sure to check the type before attempting to directly introspect an operation's `request` property.
@param url The path to match for the cancelled requests.
@param method The HTTP method to match for the cancelled requests, such as `GET`, `POST`, `PUT`, or `DELETE`. If `nil`, all request operations with URLs matching the path will be cancelled.
@param path The path appended to the HTTP client base URL to match against the cancelled requests. If `nil`, no path will be appended to the base URL.
*/ */
- (void)cancelAllHTTPOperationsWithMethod:(NSString *)method path:(NSString *)path; - (void)cancelAllHTTPOperationsWithMethod:(NSString *)method path:(NSString *)path;
@ -348,26 +346,26 @@ extern NSString * AFQueryStringFromParametersWithEncoding(NSDictionary *paramete
/** /**
Creates and enqueues an `AFHTTPRequestOperation` to the HTTP client's operation queue for each specified request object into a batch. When each request operation finishes, the specified progress block is executed, until all of the request operations have finished, at which point the completion block also executes. Creates and enqueues an `AFHTTPRequestOperation` to the HTTP client's operation queue for each specified request object into a batch. When each request operation finishes, the specified progress block is executed, until all of the request operations have finished, at which point the completion block also executes.
Operations are created by passing the specified `NSURLRequest` objects in `requests`, using `-HTTPRequestOperationWithRequest:success:failure:`, with `nil` for both the `success` and `failure` parameters.
@param requests The `NSURLRequest` objects used to create and enqueue operations. @param urlRequests The `NSURLRequest` objects used to create and enqueue operations.
@param progressBlock A block object to be executed upon the completion of each request operation in the batch. This block has no return value and takes two arguments: the number of operations that have already finished execution, and the total number of operations. @param progressBlock A block object to be executed upon the completion of each request operation in the batch. This block has no return value and takes two arguments: the number of operations that have already finished execution, and the total number of operations.
@param completionBlock A block object to be executed upon the completion of all of the request operations in the batch. This block has no return value and takes a single argument: the batched request operations. @param completionBlock A block object to be executed upon the completion of all of the request operations in the batch. This block has no return value and takes a single argument: the batched request operations.
@discussion Operations are created by passing the specified `NSURLRequest` objects in `requests`, using `-HTTPRequestOperationWithRequest:success:failure:`, with `nil` for both the `success` and `failure` parameters.
*/ */
- (void)enqueueBatchOfHTTPRequestOperationsWithRequests:(NSArray *)requests - (void)enqueueBatchOfHTTPRequestOperationsWithRequests:(NSArray *)urlRequests
progressBlock:(void (^)(NSUInteger numberOfCompletedOperations, NSUInteger totalNumberOfOperations))progressBlock progressBlock:(void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations))progressBlock
completionBlock:(void (^)(NSArray *operations))completionBlock; completionBlock:(void (^)(NSArray *operations))completionBlock;
/** /**
Enqueues the specified request operations into a batch. When each request operation finishes, the specified progress block is executed, until all of the request operations have finished, at which point the completion block also executes. Enqueues the specified request operations into a batch. When each request operation finishes, the specified progress block is executed, until all of the request operations have finished, at which point the completion block also executes.
@param operations The request operations used to be batched and enqueued. @param operations The request operations used to be batched and enqueued.
@param progressBlock A block object to be executed upon the completion of each request operation in the batch. This block has no return value and takes two arguments: the number of operations that have already finished execution, and the total number of operations. @param progressBlock A block object to be executed upon the completion of each request operation in the batch. This block has no return value and takes two arguments: the number of operations that have already finished execution, and the total number of operations.
@param completionBlock A block object to be executed upon the completion of all of the request operations in the batch. This block has no return value and takes a single argument: the batched request operations. @param completionBlock A block object to be executed upon the completion of all of the request operations in the batch. This block has no return value and takes a single argument: the batched request operations.
*/ */
- (void)enqueueBatchOfHTTPRequestOperations:(NSArray *)operations - (void)enqueueBatchOfHTTPRequestOperations:(NSArray *)operations
progressBlock:(void (^)(NSUInteger numberOfCompletedOperations, NSUInteger totalNumberOfOperations))progressBlock progressBlock:(void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations))progressBlock
completionBlock:(void (^)(NSArray *operations))completionBlock; completionBlock:(void (^)(NSArray *operations))completionBlock;
///--------------------------- ///---------------------------
@ -376,13 +374,13 @@ extern NSString * AFQueryStringFromParametersWithEncoding(NSDictionary *paramete
/** /**
Creates an `AFHTTPRequestOperation` with a `GET` request, and enqueues it to the HTTP client's operation queue. Creates an `AFHTTPRequestOperation` with a `GET` request, and enqueues it to the HTTP client's operation queue.
@param path The path to be appended to the HTTP client's base URL and used as the request URL. @param path The path to be appended to the HTTP client's base URL and used as the request URL.
@param parameters The parameters to be encoded and appended as the query string for the request URL. @param parameters The parameters to be encoded and appended as the query string for the request URL.
@param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request. @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request.
@param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes two arguments: the created request operation and the `NSError` object describing the network or parsing error that occurred.
@see HTTPRequestOperationWithRequest:success:failure @see -HTTPRequestOperationWithRequest:success:failure:
*/ */
- (void)getPath:(NSString *)path - (void)getPath:(NSString *)path
parameters:(NSDictionary *)parameters parameters:(NSDictionary *)parameters
@ -391,126 +389,253 @@ extern NSString * AFQueryStringFromParametersWithEncoding(NSDictionary *paramete
/** /**
Creates an `AFHTTPRequestOperation` with a `POST` request, and enqueues it to the HTTP client's operation queue. Creates an `AFHTTPRequestOperation` with a `POST` request, and enqueues it to the HTTP client's operation queue.
@param path The path to be appended to the HTTP client's base URL and used as the request URL. @param path The path to be appended to the HTTP client's base URL and used as the request URL.
@param parameters The parameters to be encoded and set in the request HTTP body. @param parameters The parameters to be encoded and set in the request HTTP body.
@param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request. @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request.
@param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes two arguments: the created request operation and the `NSError` object describing the network or parsing error that occurred.
@see HTTPRequestOperationWithRequest:success:failure @see -HTTPRequestOperationWithRequest:success:failure:
*/ */
- (void)postPath:(NSString *)path - (void)postPath:(NSString *)path
parameters:(NSDictionary *)parameters parameters:(NSDictionary *)parameters
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure;
/** /**
Creates an `AFHTTPRequestOperation` with a `PUT` request, and enqueues it to the HTTP client's operation queue. Creates an `AFHTTPRequestOperation` with a `PUT` request, and enqueues it to the HTTP client's operation queue.
@param path The path to be appended to the HTTP client's base URL and used as the request URL. @param path The path to be appended to the HTTP client's base URL and used as the request URL.
@param parameters The parameters to be encoded and set in the request HTTP body. @param parameters The parameters to be encoded and set in the request HTTP body.
@param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request. @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request.
@param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes two arguments: the created request operation and the `NSError` object describing the network or parsing error that occurred.
@see HTTPRequestOperationWithRequest:success:failure @see -HTTPRequestOperationWithRequest:success:failure:
*/ */
- (void)putPath:(NSString *)path - (void)putPath:(NSString *)path
parameters:(NSDictionary *)parameters parameters:(NSDictionary *)parameters
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure;
/** /**
Creates an `AFHTTPRequestOperation` with a `DELETE` request, and enqueues it to the HTTP client's operation queue. Creates an `AFHTTPRequestOperation` with a `DELETE` request, and enqueues it to the HTTP client's operation queue.
@param path The path to be appended to the HTTP client's base URL and used as the request URL. @param path The path to be appended to the HTTP client's base URL and used as the request URL.
@param parameters The parameters to be encoded and set in the request HTTP body. @param parameters The parameters to be encoded and appended as the query string for the request URL.
@param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request. @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request.
@param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes two arguments: the created request operation and the `NSError` object describing the network or parsing error that occurred.
@see HTTPRequestOperationWithRequest:success:failure @see -HTTPRequestOperationWithRequest:success:failure:
*/ */
- (void)deletePath:(NSString *)path - (void)deletePath:(NSString *)path
parameters:(NSDictionary *)parameters parameters:(NSDictionary *)parameters
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure;
/** /**
Creates an `AFHTTPRequestOperation` with a `PATCH` request, and enqueues it to the HTTP client's operation queue. Creates an `AFHTTPRequestOperation` with a `PATCH` request, and enqueues it to the HTTP client's operation queue.
@param path The path to be appended to the HTTP client's base URL and used as the request URL. @param path The path to be appended to the HTTP client's base URL and used as the request URL.
@param parameters The parameters to be encoded and set in the request HTTP body. @param parameters The parameters to be encoded and set in the request HTTP body.
@param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request. @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request.
@param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes two arguments: the created request operation and the `NSError` object describing the network or parsing error that occurred.
@see HTTPRequestOperationWithRequest:success:failure @see -HTTPRequestOperationWithRequest:success:failure:
*/ */
- (void)patchPath:(NSString *)path - (void)patchPath:(NSString *)path
parameters:(NSDictionary *)parameters parameters:(NSDictionary *)parameters
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure;
@end @end
#pragma mark - ///----------------
/// @name Constants
///----------------
/** /**
The `AFMultipartFormData` protocol defines the methods supported by the parameter in the block argument of `multipartFormRequestWithMethod:path:parameters:constructingBodyWithBlock:`. ## Network Reachability
The following constants are provided by `AFHTTPClient` as possible network reachability statuses.
enum {
AFNetworkReachabilityStatusUnknown,
AFNetworkReachabilityStatusNotReachable,
AFNetworkReachabilityStatusReachableViaWWAN,
AFNetworkReachabilityStatusReachableViaWiFi,
}
`AFNetworkReachabilityStatusUnknown`
The `baseURL` host reachability is not known.
`AFNetworkReachabilityStatusNotReachable`
The `baseURL` host cannot be reached.
`AFNetworkReachabilityStatusReachableViaWWAN`
The `baseURL` host can be reached via a cellular connection, such as EDGE or GPRS.
`AFNetworkReachabilityStatusReachableViaWiFi`
The `baseURL` host can be reached via a Wi-Fi connection.
### Keys for Notification UserInfo Dictionary
Strings that are used as keys in a `userInfo` dictionary in a network reachability status change notification.
`AFNetworkingReachabilityNotificationStatusItem`
A key in the userInfo dictionary in a `AFNetworkingReachabilityDidChangeNotification` notification.
The corresponding value is an `NSNumber` object representing the `AFNetworkReachabilityStatus` value for the current reachability status.
## Parameter Encoding
The following constants are provided by `AFHTTPClient` as possible methods for serializing parameters into query string or message body values.
enum {
AFFormURLParameterEncoding,
AFJSONParameterEncoding,
AFPropertyListParameterEncoding,
}
`AFFormURLParameterEncoding`
Parameters are encoded into field/key pairs in the URL query string for `GET` `HEAD` and `DELETE` requests, and in the message body otherwise. Dictionary keys are sorted with the `caseInsensitiveCompare:` selector of their description, in order to mitigate the possibility of ambiguous query strings being generated non-deterministically. See the warning for the `parameterEncoding` property for additional information.
`AFJSONParameterEncoding`
Parameters are encoded into JSON in the message body.
`AFPropertyListParameterEncoding`
Parameters are encoded into a property list in the message body.
*/
///----------------
/// @name Functions
///----------------
/**
Returns a query string constructed by a set of parameters, using the specified encoding.
Query strings are constructed by collecting each key-value pair, percent escaping a string representation of the key-value pair, and then joining the pairs with "&".
@see `AFHTTPClient -multipartFormRequestWithMethod:path:parameters:constructingBodyWithBlock:` If a query string pair has a an `NSArray` for its value, each member of the array will be represented in the format `field[]=value1&field[]value2`. Otherwise, the pair will be formatted as "field=value". String representations of both keys and values are derived using the `-description` method. The constructed query string does not include the ? character used to delimit the query component.
@param parameters The parameters used to construct the query string
@param encoding The encoding to use in constructing the query string. If you are uncertain of the correct encoding, you should use UTF-8 (`NSUTF8StringEncoding`), which is the encoding designated by RFC 3986 as the correct encoding for use in URLs.
@return A percent-escaped query string
*/
extern NSString * AFQueryStringFromParametersWithEncoding(NSDictionary *parameters, NSStringEncoding encoding);
///--------------------
/// @name Notifications
///--------------------
/**
Posted when network reachability changes.
This notification assigns no notification object. The `userInfo` dictionary contains an `NSNumber` object under the `AFNetworkingReachabilityNotificationStatusItem` key, representing the `AFNetworkReachabilityStatus` value for the current network reachability.
@warning In order for network reachability to be monitored, include the `SystemConfiguration` framework in the active target's "Link Binary With Library" build phase, and add `#import <SystemConfiguration/SystemConfiguration.h>` to the header prefix of the project (`Prefix.pch`).
*/
#ifdef _SYSTEMCONFIGURATION_H
extern NSString * const AFNetworkingReachabilityDidChangeNotification;
extern NSString * const AFNetworkingReachabilityNotificationStatusItem;
#endif
#pragma mark -
extern NSUInteger const kAFUploadStream3GSuggestedPacketSize;
extern NSTimeInterval const kAFUploadStream3GSuggestedDelay;
/**
The `AFMultipartFormData` protocol defines the methods supported by the parameter in the block argument of `AFHTTPClient -multipartFormRequestWithMethod:path:parameters:constructingBodyWithBlock:`.
*/ */
@protocol AFMultipartFormData @protocol AFMultipartFormData
/** /**
Appends HTTP headers, followed by the encoded data and the multipart form boundary. Appends the HTTP header `Content-Disposition: file; filename=#{generated filename}; name=#{name}"` and `Content-Type: #{generated mimeType}`, followed by the encoded file data and the multipart form boundary.
@param headers The HTTP headers to be appended to the form data.
@param body The data to be encoded and appended to the form data.
*/
- (void)appendPartWithHeaders:(NSDictionary *)headers body:(NSData *)body;
/** The filename and MIME type for this data in the form will be automatically generated, using the last path component of the `fileURL` and system associated MIME type for the `fileURL` extension, respectively.
Appends the HTTP headers `Content-Disposition: form-data; name=#{name}"`, followed by the encoded data and the multipart form boundary.
@param data The data to be encoded and appended to the form data. @param fileURL The URL corresponding to the file whose content will be appended to the form. This parameter must not be `nil`.
@param name The name to be associated with the specified data. This parameter must not be `nil`. @param name The name to be associated with the specified data. This parameter must not be `nil`.
@param error If an error occurs, upon return contains an `NSError` object that describes the problem.
@return `YES` if the file data was successfully appended, otherwise `NO`.
*/ */
- (void)appendPartWithFormData:(NSData *)data name:(NSString *)name; - (BOOL)appendPartWithFileURL:(NSURL *)fileURL
name:(NSString *)name
error:(NSError * __autoreleasing *)error;
/** /**
Appends the HTTP header `Content-Disposition: file; filename=#{filename}; name=#{name}"` and `Content-Type: #{mimeType}`, followed by the encoded file data and the multipart form boundary. Appends the HTTP header `Content-Disposition: file; filename=#{filename}; name=#{name}"` and `Content-Type: #{mimeType}`, followed by the encoded file data and the multipart form boundary.
@param data The data to be encoded and appended to the form data.
@param name The name to be associated with the specified data. This parameter must not be `nil`.
@param mimeType The MIME type of the specified data. (For example, the MIME type for a JPEG image is image/jpeg.) For a list of valid MIME types, see http://www.iana.org/assignments/media-types/. This parameter must not be `nil`.
@param filename The filename to be associated with the specified data. This parameter must not be `nil`.
*/
- (void)appendPartWithFileData:(NSData *)data name:(NSString *)name fileName:(NSString *)fileName mimeType:(NSString *)mimeType;
/** @param fileURL The URL corresponding to the file whose content will be appended to the form. This parameter must not be `nil`.
Appends the HTTP header `Content-Disposition: file; filename=#{generated filename}; name=#{name}"` and `Content-Type: #{generated mimeType}`, followed by the encoded file data and the multipart form boundary.
@param fileURL The URL corresponding to the file whose content will be appended to the form.
@param name The name to be associated with the specified data. This parameter must not be `nil`. @param name The name to be associated with the specified data. This parameter must not be `nil`.
@param fileName The file name to be used in the `Content-Disposition` header. This parameter must not be `nil`.
@param mimeType The declared MIME type of the file data. This parameter must not be `nil`.
@param error If an error occurs, upon return contains an `NSError` object that describes the problem. @param error If an error occurs, upon return contains an `NSError` object that describes the problem.
@return `YES` if the file data was successfully appended, otherwise `NO`. @return `YES` if the file data was successfully appended otherwise `NO`.
@discussion The filename and MIME type for this data in the form will be automatically generated, using `NSURLResponse` `-suggestedFilename` and `-MIMEType`, respectively.
*/ */
- (BOOL)appendPartWithFileURL:(NSURL *)fileURL name:(NSString *)name error:(NSError **)error; - (BOOL)appendPartWithFileURL:(NSURL *)fileURL
name:(NSString *)name
fileName:(NSString *)fileName
mimeType:(NSString *)mimeType
error:(NSError * __autoreleasing *)error;
/** /**
Appends encoded data to the form data. Appends the HTTP header `Content-Disposition: file; filename=#{filename}; name=#{name}"` and `Content-Type: #{mimeType}`, followed by the data from the input stream and the multipart form boundary.
@param inputStream The input stream to be appended to the form data
@param name The name to be associated with the specified input stream. This parameter must not be `nil`.
@param fileName The filename to be associated with the specified input stream. This parameter must not be `nil`.
@param length The length of the specified input stream in bytes.
@param mimeType The MIME type of the specified data. (For example, the MIME type for a JPEG image is image/jpeg.) For a list of valid MIME types, see http://www.iana.org/assignments/media-types/. This parameter must not be `nil`.
*/
- (void)appendPartWithInputStream:(NSInputStream *)inputStream
name:(NSString *)name
fileName:(NSString *)fileName
length:(unsigned long long)length
mimeType:(NSString *)mimeType;
/**
Appends the HTTP header `Content-Disposition: file; filename=#{filename}; name=#{name}"` and `Content-Type: #{mimeType}`, followed by the encoded file data and the multipart form boundary.
@param data The data to be encoded and appended to the form data. @param data The data to be encoded and appended to the form data.
@param name The name to be associated with the specified data. This parameter must not be `nil`.
@param fileName The filename to be associated with the specified data. This parameter must not be `nil`.
@param mimeType The MIME type of the specified data. (For example, the MIME type for a JPEG image is image/jpeg.) For a list of valid MIME types, see http://www.iana.org/assignments/media-types/. This parameter must not be `nil`.
*/ */
- (void)appendData:(NSData *)data; - (void)appendPartWithFileData:(NSData *)data
name:(NSString *)name
fileName:(NSString *)fileName
mimeType:(NSString *)mimeType;
/** /**
Appends a string to the form data. Appends the HTTP headers `Content-Disposition: form-data; name=#{name}"`, followed by the encoded data and the multipart form boundary.
@param string The string to be encoded and appended to the form data. @param data The data to be encoded and appended to the form data.
@param name The name to be associated with the specified data. This parameter must not be `nil`.
*/ */
- (void)appendString:(NSString *)string;
- (void)appendPartWithFormData:(NSData *)data
name:(NSString *)name;
/**
Appends HTTP headers, followed by the encoded data and the multipart form boundary.
@param headers The HTTP headers to be appended to the form data.
@param body The data to be encoded and appended to the form data.
*/
- (void)appendPartWithHeaders:(NSDictionary *)headers
body:(NSData *)body;
/**
Throttles request bandwidth by limiting the packet size and adding a delay for each chunk read from the upload stream.
When uploading over a 3G or EDGE connection, requests may fail with "request body stream exhausted". Setting a maximum packet size and delay according to the recommended values (`kAFUploadStream3GSuggestedPacketSize` and `kAFUploadStream3GSuggestedDelay`) lowers the risk of the input stream exceeding its allocated bandwidth. Unfortunately, as of iOS 6, there is no definite way to distinguish between a 3G, EDGE, or LTE connection. As such, it is not recommended that you throttle bandwidth based solely on network reachability. Instead, you should consider checking for the "request body stream exhausted" in a failure block, and then retrying the request with throttled bandwidth.
@param numberOfBytes Maximum packet size, in number of bytes. The default packet size for an input stream is 32kb.
@param delay Duration of delay each time a packet is read. By default, no delay is set.
*/
- (void)throttleBandwidthWithPacketSize:(NSUInteger)numberOfBytes
delay:(NSTimeInterval)delay;
@end @end

1282
clients/ios/AFNetworking/AFHTTPClient.m Normal file → Executable file

File diff suppressed because it is too large Load diff

83
clients/ios/AFNetworking/AFHTTPRequestOperation.h Normal file → Executable file
View file

@ -1,17 +1,17 @@
// AFHTTPRequestOperation.h // AFHTTPRequestOperation.h
// //
// Copyright (c) 2011 Gowalla (http://gowalla.com/) // Copyright (c) 2011 Gowalla (http://gowalla.com/)
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights // in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is // copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions: // furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -23,13 +23,6 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "AFURLConnectionOperation.h" #import "AFURLConnectionOperation.h"
/**
Returns a set of MIME types detected in an HTTP `Accept` or `Content-Type` header.
*/
extern NSSet * AFContentTypesFromHTTPHeader(NSString *string);
extern NSString * AFCreateIncompleteDownloadDirectoryPath(void);
/** /**
`AFHTTPRequestOperation` is a subclass of `AFURLConnectionOperation` for requests using the HTTP or HTTPS protocols. It encapsulates the concept of acceptable status codes and content types, which determine the success or failure of a request. `AFHTTPRequestOperation` is a subclass of `AFURLConnectionOperation` for requests using the HTTP or HTTPS protocols. It encapsulates the concept of acceptable status codes and content types, which determine the success or failure of a request.
*/ */
@ -42,31 +35,7 @@ extern NSString * AFCreateIncompleteDownloadDirectoryPath(void);
/** /**
The last HTTP response received by the operation's connection. The last HTTP response received by the operation's connection.
*/ */
@property (readonly, nonatomic, retain) NSHTTPURLResponse *response; @property (readonly, nonatomic, strong) NSHTTPURLResponse *response;
/**
Set a target file for the response, will stream directly into this destination.
Defaults to nil, which will use a memory stream. Will create a new outputStream on change.
Note: Changing this while the request is not in ready state will be ignored.
*/
@property (nonatomic, copy) NSString *responseFilePath;
/**
Expected total length. This is different than expectedContentLength if the file is resumed.
On regular requests, this is equal to self.response.expectedContentLength unless we resume a request.
Note: this can also be -1 if the file size is not sent (*)
*/
@property (assign, readonly) long long totalContentLength;
/**
Indicator for the file offset on partial/resumed downloads.
This is greater than zero if the file download is resumed.
*/
@property (assign, readonly) long long offsetContentLength;
///---------------------------------------------------------- ///----------------------------------------------------------
/// @name Managing And Checking For Acceptable HTTP Responses /// @name Managing And Checking For Acceptable HTTP Responses
@ -75,50 +44,50 @@ extern NSString * AFCreateIncompleteDownloadDirectoryPath(void);
/** /**
A Boolean value that corresponds to whether the status code of the response is within the specified set of acceptable status codes. Returns `YES` if `acceptableStatusCodes` is `nil`. A Boolean value that corresponds to whether the status code of the response is within the specified set of acceptable status codes. Returns `YES` if `acceptableStatusCodes` is `nil`.
*/ */
@property (readonly) BOOL hasAcceptableStatusCode; @property (nonatomic, readonly) BOOL hasAcceptableStatusCode;
/** /**
A Boolean value that corresponds to whether the MIME type of the response is among the specified set of acceptable content types. Returns `YES` if `acceptableContentTypes` is `nil`. A Boolean value that corresponds to whether the MIME type of the response is among the specified set of acceptable content types. Returns `YES` if `acceptableContentTypes` is `nil`.
*/ */
@property (readonly) BOOL hasAcceptableContentType; @property (nonatomic, readonly) BOOL hasAcceptableContentType;
/** /**
The callback dispatch queue on success. If `NULL` (default), the main queue is used. The callback dispatch queue on success. If `NULL` (default), the main queue is used.
*/ */
@property (nonatomic, assign) dispatch_queue_t successCallbackQueue; @property (nonatomic, assign) dispatch_queue_t successCallbackQueue;
/** /**
The callback dispatch queue on failure. If `NULL` (default), the main queue is used. The callback dispatch queue on failure. If `NULL` (default), the main queue is used.
*/ */
@property (nonatomic, assign) dispatch_queue_t failureCallbackQueue; @property (nonatomic, assign) dispatch_queue_t failureCallbackQueue;
///------------------------------------------------------------- ///------------------------------------------------------------
/// @name Managing Accceptable HTTP Status Codes & Content Types /// @name Managing Acceptable HTTP Status Codes & Content Types
///------------------------------------------------------------- ///------------------------------------------------------------
/** /**
Returns an `NSIndexSet` object containing the ranges of acceptable HTTP status codes. When non-`nil`, the operation will set the `error` property to an error in `AFErrorDomain`. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html Returns an `NSIndexSet` object containing the ranges of acceptable HTTP status codes. When non-`nil`, the operation will set the `error` property to an error in `AFErrorDomain`. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
By default, this is the range 200 to 299, inclusive. By default, this is the range 200 to 299, inclusive.
*/ */
+ (NSIndexSet *)acceptableStatusCodes; + (NSIndexSet *)acceptableStatusCodes;
/** /**
Adds status codes to the set of acceptable HTTP status codes returned by `+acceptableStatusCodes` in subsequent calls by this class and its descendents. Adds status codes to the set of acceptable HTTP status codes returned by `+acceptableStatusCodes` in subsequent calls by this class and its descendants.
@param statusCodes The status codes to be added to the set of acceptable HTTP status codes @param statusCodes The status codes to be added to the set of acceptable HTTP status codes
*/ */
+ (void)addAcceptableStatusCodes:(NSIndexSet *)statusCodes; + (void)addAcceptableStatusCodes:(NSIndexSet *)statusCodes;
/** /**
Returns an `NSSet` object containing the acceptable MIME types. When non-`nil`, the operation will set the `error` property to an error in `AFErrorDomain`. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17 Returns an `NSSet` object containing the acceptable MIME types. When non-`nil`, the operation will set the `error` property to an error in `AFErrorDomain`. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17
By default, this is `nil`. By default, this is `nil`.
*/ */
+ (NSSet *)acceptableContentTypes; + (NSSet *)acceptableContentTypes;
/** /**
Adds content types to the set of acceptable MIME types returned by `+acceptableContentTypes` in subsequent calls by this class and its descendents. Adds content types to the set of acceptable MIME types returned by `+acceptableContentTypes` in subsequent calls by this class and its descendants.
@param contentTypes The content types to be added to the set of acceptable MIME types @param contentTypes The content types to be added to the set of acceptable MIME types
*/ */
@ -131,7 +100,7 @@ extern NSString * AFCreateIncompleteDownloadDirectoryPath(void);
/** /**
A Boolean value determining whether or not the class can process the specified request. For example, `AFJSONRequestOperation` may check to make sure the content type was `application/json` or the URL path extension was `.json`. A Boolean value determining whether or not the class can process the specified request. For example, `AFJSONRequestOperation` may check to make sure the content type was `application/json` or the URL path extension was `.json`.
@param urlRequest The request that is determined to be supported or not supported for this class. @param urlRequest The request that is determined to be supported or not supported for this class.
*/ */
+ (BOOL)canProcessRequest:(NSURLRequest *)urlRequest; + (BOOL)canProcessRequest:(NSURLRequest *)urlRequest;
@ -142,13 +111,23 @@ extern NSString * AFCreateIncompleteDownloadDirectoryPath(void);
/** /**
Sets the `completionBlock` property with a block that executes either the specified success or failure block, depending on the state of the request on completion. If `error` returns a value, which can be caused by an unacceptable status code or content type, then `failure` is executed. Otherwise, `success` is executed. Sets the `completionBlock` property with a block that executes either the specified success or failure block, depending on the state of the request on completion. If `error` returns a value, which can be caused by an unacceptable status code or content type, then `failure` is executed. Otherwise, `success` is executed.
This method should be overridden in subclasses in order to specify the response object passed into the success block.
@param success The block to be executed on the completion of a successful request. This block has no return value and takes two arguments: the receiver operation and the object constructed from the response data of the request. @param success The block to be executed on the completion of a successful request. This block has no return value and takes two arguments: the receiver operation and the object constructed from the response data of the request.
@param failure The block to be executed on the completion of an unsuccessful request. This block has no return value and takes two arguments: the receiver operation and the error that occured during the request. @param failure The block to be executed on the completion of an unsuccessful request. This block has no return value and takes two arguments: the receiver operation and the error that occurred during the request.
@discussion This method should be overridden in subclasses in order to specify the response object passed into the success block.
*/ */
- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success - (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure;
@end @end
///----------------
/// @name Functions
///----------------
/**
Returns a set of MIME types detected in an HTTP `Accept` or `Content-Type` header.
*/
extern NSSet * AFContentTypesFromHTTPHeader(NSString *string);

288
clients/ios/AFNetworking/AFHTTPRequestOperation.m Normal file → Executable file
View file

@ -1,17 +1,17 @@
// AFHTTPRequestOperation.m // AFHTTPRequestOperation.m
// //
// Copyright (c) 2011 Gowalla (http://gowalla.com/) // Copyright (c) 2011 Gowalla (http://gowalla.com/)
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights // in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is // copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions: // furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -23,42 +23,50 @@
#import "AFHTTPRequestOperation.h" #import "AFHTTPRequestOperation.h"
#import <objc/runtime.h> #import <objc/runtime.h>
NSString * const kAFNetworkingIncompleteDownloadDirectoryName = @"Incomplete"; // Workaround for change in imp_implementationWithBlock() with Xcode 4.5
#if defined(__IPHONE_6_0) || defined(__MAC_10_8)
#define AF_CAST_TO_BLOCK id
#else
#define AF_CAST_TO_BLOCK __bridge void *
#endif
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wstrict-selector-match"
NSSet * AFContentTypesFromHTTPHeader(NSString *string) { NSSet * AFContentTypesFromHTTPHeader(NSString *string) {
static NSCharacterSet *_skippedCharacterSet = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_skippedCharacterSet = [[NSCharacterSet characterSetWithCharactersInString:@" ,"] retain];
});
if (!string) { if (!string) {
return nil; return nil;
} }
NSScanner *scanner = [NSScanner scannerWithString:string]; NSArray *mediaRanges = [string componentsSeparatedByString:@","];
scanner.charactersToBeSkipped = _skippedCharacterSet; NSMutableSet *mutableContentTypes = [NSMutableSet setWithCapacity:mediaRanges.count];
NSMutableSet *mutableContentTypes = [NSMutableSet set]; [mediaRanges enumerateObjectsUsingBlock:^(NSString *mediaRange, __unused NSUInteger idx, __unused BOOL *stop) {
while (![scanner isAtEnd]) { NSRange parametersRange = [mediaRange rangeOfString:@";"];
NSString *contentType = nil; if (parametersRange.location != NSNotFound) {
if ([scanner scanUpToString:@";" intoString:&contentType]) { mediaRange = [mediaRange substringToIndex:parametersRange.location];
[scanner scanUpToString:@"," intoString:nil];
} }
if (contentType) { mediaRange = [mediaRange stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[mutableContentTypes addObject:contentType];
if (mediaRange.length > 0) {
[mutableContentTypes addObject:mediaRange];
} }
} }];
return [NSSet setWithSet:mutableContentTypes]; return [NSSet setWithSet:mutableContentTypes];
} }
static void AFSwizzleClassMethodWithImplementation(Class klass, SEL selector, IMP implementation) { static void AFGetMediaTypeAndSubtypeWithString(NSString *string, NSString **type, NSString **subtype) {
Method originalMethod = class_getClassMethod(klass, selector); if (!string) {
if (method_getImplementation(originalMethod) != implementation) { return;
class_replaceMethod(objc_getMetaClass([NSStringFromClass(klass) UTF8String]), selector, implementation, method_getTypeEncoding(originalMethod));
} }
NSScanner *scanner = [NSScanner scannerWithString:string];
[scanner setCharactersToBeSkipped:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[scanner scanUpToString:@"/" intoString:type];
[scanner scanString:@"/" intoString:nil];
[scanner scanUpToString:@";" intoString:subtype];
} }
static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) { static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) {
@ -77,11 +85,11 @@ static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) {
} }
if (range.length == 1) { if (range.length == 1) {
[string appendFormat:@"%u", range.location]; [string appendFormat:@"%lu", (long)range.location];
} else { } else {
NSUInteger firstIndex = range.location; NSUInteger firstIndex = range.location;
NSUInteger lastIndex = firstIndex + range.length - 1; NSUInteger lastIndex = firstIndex + range.length - 1;
[string appendFormat:@"%u-%u", firstIndex, lastIndex]; [string appendFormat:@"%lu-%lu", (long)firstIndex, (long)lastIndex];
} }
range.location = nextIndex; range.location = nextIndex;
@ -91,77 +99,66 @@ static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) {
return string; return string;
} }
NSString * AFCreateIncompleteDownloadDirectoryPath(void) { static void AFSwizzleClassMethodWithClassAndSelectorUsingBlock(Class klass, SEL selector, id block) {
static NSString *incompleteDownloadPath; Method originalMethod = class_getClassMethod(klass, selector);
static dispatch_once_t onceToken; IMP implementation = imp_implementationWithBlock((AF_CAST_TO_BLOCK)block);
dispatch_once(&onceToken, ^{ class_replaceMethod(objc_getMetaClass([NSStringFromClass(klass) UTF8String]), selector, implementation, method_getTypeEncoding(originalMethod));
NSString *tempDirectory = NSTemporaryDirectory();
incompleteDownloadPath = [[tempDirectory stringByAppendingPathComponent:kAFNetworkingIncompleteDownloadDirectoryName] retain];
NSError *error = nil;
NSFileManager *fileMan = [[NSFileManager alloc] init];
if(![fileMan createDirectoryAtPath:incompleteDownloadPath withIntermediateDirectories:YES attributes:nil error:&error]) {
NSLog(@"Failed to create incomplete downloads directory at %@", incompleteDownloadPath);
}
[fileMan release];
});
return incompleteDownloadPath;
} }
#pragma mark - #pragma mark -
@interface AFHTTPRequestOperation () @interface AFHTTPRequestOperation ()
@property (readwrite, nonatomic, retain) NSURLRequest *request; @property (readwrite, nonatomic, strong) NSURLRequest *request;
@property (readwrite, nonatomic, retain) NSHTTPURLResponse *response; @property (readwrite, nonatomic, strong) NSHTTPURLResponse *response;
@property (readwrite, nonatomic, retain) NSError *HTTPError; @property (readwrite, nonatomic, strong) NSError *HTTPError;
@property (assign) long long totalContentLength;
@property (assign) long long offsetContentLength;
@end @end
@implementation AFHTTPRequestOperation @implementation AFHTTPRequestOperation
@synthesize HTTPError = _HTTPError; @synthesize HTTPError = _HTTPError;
@synthesize responseFilePath = _responseFilePath;
@synthesize successCallbackQueue = _successCallbackQueue; @synthesize successCallbackQueue = _successCallbackQueue;
@synthesize failureCallbackQueue = _failureCallbackQueue; @synthesize failureCallbackQueue = _failureCallbackQueue;
@synthesize totalContentLength = _totalContentLength;
@synthesize offsetContentLength = _offsetContentLength;
@dynamic request; @dynamic request;
@dynamic response; @dynamic response;
- (void)dealloc { - (void)dealloc {
[_HTTPError release]; if (_successCallbackQueue) {
#if !OS_OBJECT_USE_OBJC
if (_successCallbackQueue) {
dispatch_release(_successCallbackQueue); dispatch_release(_successCallbackQueue);
#endif
_successCallbackQueue = NULL; _successCallbackQueue = NULL;
} }
if (_failureCallbackQueue) { if (_failureCallbackQueue) {
dispatch_release(_failureCallbackQueue); #if !OS_OBJECT_USE_OBJC
dispatch_release(_failureCallbackQueue);
#endif
_failureCallbackQueue = NULL; _failureCallbackQueue = NULL;
} }
[super dealloc];
} }
- (NSError *)error { - (NSError *)error {
if (self.response && !self.HTTPError) { if (!self.HTTPError && self.response) {
if (![self hasAcceptableStatusCode]) { if (![self hasAcceptableStatusCode] || ![self hasAcceptableContentType]) {
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
[userInfo setValue:[NSString stringWithFormat:NSLocalizedString(@"Expected status code in (%@), got %d", nil), AFStringFromIndexSet([[self class] acceptableStatusCodes]), [self.response statusCode]] forKey:NSLocalizedDescriptionKey]; [userInfo setValue:self.responseString forKey:NSLocalizedRecoverySuggestionErrorKey];
[userInfo setValue:[self.request URL] forKey:NSURLErrorFailingURLErrorKey]; [userInfo setValue:[self.request URL] forKey:NSURLErrorFailingURLErrorKey];
[userInfo setValue:self.request forKey:AFNetworkingOperationFailingURLRequestErrorKey];
self.HTTPError = [[[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorBadServerResponse userInfo:userInfo] autorelease]; [userInfo setValue:self.response forKey:AFNetworkingOperationFailingURLResponseErrorKey];
} else if ([self.responseData length] > 0 && ![self hasAcceptableContentType]) { // Don't invalidate content type if there is no content
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; if (![self hasAcceptableStatusCode]) {
[userInfo setValue:[NSString stringWithFormat:NSLocalizedString(@"Expected content type %@, got %@", nil), [[self class] acceptableContentTypes], [self.response MIMEType]] forKey:NSLocalizedDescriptionKey]; NSUInteger statusCode = ([self.response isKindOfClass:[NSHTTPURLResponse class]]) ? (NSUInteger)[self.response statusCode] : 200;
[userInfo setValue:[self.request URL] forKey:NSURLErrorFailingURLErrorKey]; [userInfo setValue:[NSString stringWithFormat:NSLocalizedStringFromTable(@"Expected status code in (%@), got %d", @"AFNetworking", nil), AFStringFromIndexSet([[self class] acceptableStatusCodes]), statusCode] forKey:NSLocalizedDescriptionKey];
self.HTTPError = [[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorBadServerResponse userInfo:userInfo];
self.HTTPError = [[[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:userInfo] autorelease]; } else if (![self hasAcceptableContentType]) {
// Don't invalidate content type if there is no content
if ([self.responseData length] > 0) {
[userInfo setValue:[NSString stringWithFormat:NSLocalizedStringFromTable(@"Expected content type %@, got %@", @"AFNetworking", nil), [[self class] acceptableContentTypes], [self.response MIMEType]] forKey:NSLocalizedDescriptionKey];
self.HTTPError = [[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:userInfo];
}
}
} }
} }
if (self.HTTPError) { if (self.HTTPError) {
return self.HTTPError; return self.HTTPError;
} else { } else {
@ -169,113 +166,136 @@ NSString * AFCreateIncompleteDownloadDirectoryPath(void) {
} }
} }
- (NSStringEncoding)responseStringEncoding {
// When no explicit charset parameter is provided by the sender, media subtypes of the "text" type are defined to have a default charset value of "ISO-8859-1" when received via HTTP. Data in character sets other than "ISO-8859-1" or its subsets MUST be labeled with an appropriate charset value.
// See http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.4.1
if (self.response && !self.response.textEncodingName && self.responseData && [self.response respondsToSelector:@selector(allHeaderFields)]) {
NSString *type = nil;
AFGetMediaTypeAndSubtypeWithString([[self.response allHeaderFields] valueForKey:@"Content-Type"], &type, nil);
if ([type isEqualToString:@"text"]) {
return NSISOLatin1StringEncoding;
}
}
return [super responseStringEncoding];
}
- (void)pause { - (void)pause {
unsigned long long offset = 0; unsigned long long offset = 0;
if ([self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey]) { if ([self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey]) {
offset = [[self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey] unsignedLongLongValue]; offset = [[self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey] unsignedLongLongValue];
} else { } else {
offset = [[self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey] length]; offset = [[self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey] length];
} }
NSMutableURLRequest *mutableURLRequest = [[self.request mutableCopy] autorelease]; NSMutableURLRequest *mutableURLRequest = [self.request mutableCopy];
if ([[self.response allHeaderFields] valueForKey:@"ETag"]) { if ([self.response respondsToSelector:@selector(allHeaderFields)] && [[self.response allHeaderFields] valueForKey:@"ETag"]) {
[mutableURLRequest setValue:[[self.response allHeaderFields] valueForKey:@"ETag"] forHTTPHeaderField:@"If-Range"]; [mutableURLRequest setValue:[[self.response allHeaderFields] valueForKey:@"ETag"] forHTTPHeaderField:@"If-Range"];
} }
[mutableURLRequest setValue:[NSString stringWithFormat:@"bytes=%llu-", offset] forHTTPHeaderField:@"Range"]; [mutableURLRequest setValue:[NSString stringWithFormat:@"bytes=%llu-", offset] forHTTPHeaderField:@"Range"];
self.request = mutableURLRequest; self.request = mutableURLRequest;
[super pause]; [super pause];
} }
- (BOOL)hasAcceptableStatusCode { - (BOOL)hasAcceptableStatusCode {
return ![[self class] acceptableStatusCodes] || [[[self class] acceptableStatusCodes] containsIndex:[self.response statusCode]]; if (!self.response) {
return NO;
}
NSUInteger statusCode = ([self.response isKindOfClass:[NSHTTPURLResponse class]]) ? (NSUInteger)[self.response statusCode] : 200;
return ![[self class] acceptableStatusCodes] || [[[self class] acceptableStatusCodes] containsIndex:statusCode];
} }
- (BOOL)hasAcceptableContentType { - (BOOL)hasAcceptableContentType {
return ![[self class] acceptableContentTypes] || [[[self class] acceptableContentTypes] containsObject:[self.response MIMEType]]; if (!self.response) {
return NO;
}
// Any HTTP/1.1 message containing an entity-body SHOULD include a Content-Type header field defining the media type of that body. If and only if the media type is not given by a Content-Type field, the recipient MAY attempt to guess the media type via inspection of its content and/or the name extension(s) of the URI used to identify the resource. If the media type remains unknown, the recipient SHOULD treat it as type "application/octet-stream".
// See http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html
NSString *contentType = [self.response MIMEType];
if (!contentType) {
contentType = @"application/octet-stream";
}
return ![[self class] acceptableContentTypes] || [[[self class] acceptableContentTypes] containsObject:contentType];
} }
- (void)setSuccessCallbackQueue:(dispatch_queue_t)successCallbackQueue { - (void)setSuccessCallbackQueue:(dispatch_queue_t)successCallbackQueue {
if (successCallbackQueue != _successCallbackQueue) { if (successCallbackQueue != _successCallbackQueue) {
if (_successCallbackQueue) { if (_successCallbackQueue) {
#if !OS_OBJECT_USE_OBJC
dispatch_release(_successCallbackQueue); dispatch_release(_successCallbackQueue);
#endif
_successCallbackQueue = NULL; _successCallbackQueue = NULL;
} }
if (successCallbackQueue) { if (successCallbackQueue) {
#if !OS_OBJECT_USE_OBJC
dispatch_retain(successCallbackQueue); dispatch_retain(successCallbackQueue);
#endif
_successCallbackQueue = successCallbackQueue; _successCallbackQueue = successCallbackQueue;
} }
} }
} }
- (void)setFailureCallbackQueue:(dispatch_queue_t)failureCallbackQueue { - (void)setFailureCallbackQueue:(dispatch_queue_t)failureCallbackQueue {
if (failureCallbackQueue != _failureCallbackQueue) { if (failureCallbackQueue != _failureCallbackQueue) {
if (_failureCallbackQueue) { if (_failureCallbackQueue) {
#if !OS_OBJECT_USE_OBJC
dispatch_release(_failureCallbackQueue); dispatch_release(_failureCallbackQueue);
#endif
_failureCallbackQueue = NULL; _failureCallbackQueue = NULL;
} }
if (failureCallbackQueue) { if (failureCallbackQueue) {
#if !OS_OBJECT_USE_OBJC
dispatch_retain(failureCallbackQueue); dispatch_retain(failureCallbackQueue);
#endif
_failureCallbackQueue = failureCallbackQueue; _failureCallbackQueue = failureCallbackQueue;
} }
} }
} }
- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success - (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{ {
self.completionBlock = ^ { // completionBlock is manually nilled out in AFURLConnectionOperation to break the retain cycle.
if ([self isCancelled]) { #pragma clang diagnostic push
return; #pragma clang diagnostic ignored "-Warc-retain-cycles"
} #pragma clang diagnostic ignored "-Wgnu"
self.completionBlock = ^{
if (self.error) { if (self.error) {
if (failure) { if (failure) {
dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ dispatch_async(self.failureCallbackQueue ?: dispatch_get_main_queue(), ^{
failure(self, self.error); failure(self, self.error);
}); });
} }
} else { } else {
if (success) { if (success) {
dispatch_async(self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ dispatch_async(self.successCallbackQueue ?: dispatch_get_main_queue(), ^{
success(self, self.responseData); success(self, self.responseData);
}); });
} }
} }
}; };
} #pragma clang diagnostic pop
- (void)setResponseFilePath:(NSString *)responseFilePath {
if ([self isReady] && responseFilePath != _responseFilePath) {
[_responseFilePath release];
_responseFilePath = [responseFilePath retain];
if (responseFilePath) {
self.outputStream = [NSOutputStream outputStreamToFileAtPath:responseFilePath append:NO];
}else {
self.outputStream = [NSOutputStream outputStreamToMemory];
}
}
} }
#pragma mark - AFHTTPRequestOperation #pragma mark - AFHTTPRequestOperation
static id AFStaticClassValueImplementation(id self, SEL _cmd) {
return objc_getAssociatedObject([self class], _cmd);
}
+ (NSIndexSet *)acceptableStatusCodes { + (NSIndexSet *)acceptableStatusCodes {
return [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)]; return [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)];
} }
+ (void)addAcceptableStatusCodes:(NSIndexSet *)statusCodes { + (void)addAcceptableStatusCodes:(NSIndexSet *)statusCodes {
NSMutableIndexSet *mutableStatusCodes = [[[NSMutableIndexSet alloc] initWithIndexSet:[self acceptableStatusCodes]] autorelease]; NSMutableIndexSet *mutableStatusCodes = [[NSMutableIndexSet alloc] initWithIndexSet:[self acceptableStatusCodes]];
[mutableStatusCodes addIndexes:statusCodes]; [mutableStatusCodes addIndexes:statusCodes];
SEL selector = @selector(acceptableStatusCodes); AFSwizzleClassMethodWithClassAndSelectorUsingBlock([self class], @selector(acceptableStatusCodes), ^(__unused id _self) {
AFSwizzleClassMethodWithImplementation([self class], selector, (IMP)AFStaticClassValueImplementation); return mutableStatusCodes;
objc_setAssociatedObject([self class], selector, mutableStatusCodes, OBJC_ASSOCIATION_COPY_NONATOMIC); });
} }
+ (NSSet *)acceptableContentTypes { + (NSSet *)acceptableContentTypes {
@ -283,53 +303,21 @@ static id AFStaticClassValueImplementation(id self, SEL _cmd) {
} }
+ (void)addAcceptableContentTypes:(NSSet *)contentTypes { + (void)addAcceptableContentTypes:(NSSet *)contentTypes {
NSMutableSet *mutableContentTypes = [[[NSMutableSet alloc] initWithSet:[self acceptableContentTypes] copyItems:YES] autorelease]; NSMutableSet *mutableContentTypes = [[NSMutableSet alloc] initWithSet:[self acceptableContentTypes] copyItems:YES];
[mutableContentTypes unionSet:contentTypes]; [mutableContentTypes unionSet:contentTypes];
SEL selector = @selector(acceptableContentTypes); AFSwizzleClassMethodWithClassAndSelectorUsingBlock([self class], @selector(acceptableContentTypes), ^(__unused id _self) {
AFSwizzleClassMethodWithImplementation([self class], selector, (IMP)AFStaticClassValueImplementation); return mutableContentTypes;
objc_setAssociatedObject([self class], selector, mutableContentTypes, OBJC_ASSOCIATION_COPY_NONATOMIC); });
} }
+ (BOOL)canProcessRequest:(NSURLRequest *)request { + (BOOL)canProcessRequest:(NSURLRequest *)request {
if ([[self class] isEqual:[AFHTTPRequestOperation class]]) { if ([[self class] isEqual:[AFHTTPRequestOperation class]]) {
return YES; return YES;
} }
return [[self acceptableContentTypes] intersectsSet:AFContentTypesFromHTTPHeader([request valueForHTTPHeaderField:@"Accept"])]; return [[self acceptableContentTypes] intersectsSet:AFContentTypesFromHTTPHeader([request valueForHTTPHeaderField:@"Accept"])];
} }
#pragma mark - NSURLConnectionDelegate
- (void)connection:(NSURLConnection *)connection
didReceiveResponse:(NSURLResponse *)response
{
self.response = (NSHTTPURLResponse *)response;
// 206 = Partial Content.
long long totalContentLength = self.response.expectedContentLength;
long long fileOffset = 0;
if ([self.response statusCode] != 206) {
if ([self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey]) {
[self.outputStream setProperty:[NSNumber numberWithInteger:0] forKey:NSStreamFileCurrentOffsetKey];
} else {
if ([[self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey] length] > 0) {
self.outputStream = [NSOutputStream outputStreamToMemory];
}
}
}else {
NSString *contentRange = [self.response.allHeaderFields valueForKey:@"Content-Range"];
if ([contentRange hasPrefix:@"bytes"]) {
NSArray *bytes = [contentRange componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@" -/"]];
if ([bytes count] == 4) {
fileOffset = [[bytes objectAtIndex:1] longLongValue];
totalContentLength = [[bytes objectAtIndex:2] longLongValue] ?: -1; // if this is *, it's converted to 0, but -1 is default.
}
}
}
self.offsetContentLength = MAX(fileOffset, 0);
self.totalContentLength = totalContentLength;
[self.outputStream open];
}
@end @end
#pragma clang diagnostic pop

81
clients/ios/AFNetworking/AFImageRequestOperation.h Normal file → Executable file
View file

@ -1,17 +1,17 @@
// AFImageRequestOperation.h // AFImageRequestOperation.h
// //
// Copyright (c) 2011 Gowalla (http://gowalla.com/) // Copyright (c) 2011 Gowalla (http://gowalla.com/)
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights // in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is // copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions: // furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -25,19 +25,19 @@
#import <Availability.h> #import <Availability.h>
#if __IPHONE_OS_VERSION_MIN_REQUIRED #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#elif __MAC_OS_X_VERSION_MIN_REQUIRED #elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#endif #endif
/** /**
`AFImageRequestOperation` is a subclass of `AFHTTPRequestOperation` for downloading an processing images. `AFImageRequestOperation` is a subclass of `AFHTTPRequestOperation` for downloading and processing images.
## Acceptable Content Types ## Acceptable Content Types
By default, `AFImageRequestOperation` accepts the following MIME types, which correspond to the image formats supported by UIImage or NSImage: By default, `AFImageRequestOperation` accepts the following MIME types, which correspond to the image formats supported by UIImage or NSImage:
- `image/tiff` - `image/tiff`
- `image/jpeg` - `image/jpeg`
- `image/gif` - `image/gif`
@ -54,59 +54,60 @@
/** /**
An image constructed from the response data. If an error occurs during the request, `nil` will be returned, and the `error` property will be set to the error. An image constructed from the response data. If an error occurs during the request, `nil` will be returned, and the `error` property will be set to the error.
*/ */
#if __IPHONE_OS_VERSION_MIN_REQUIRED #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
@property (readonly, nonatomic, retain) UIImage *responseImage; @property (readonly, nonatomic, strong) UIImage *responseImage;
#elif __MAC_OS_X_VERSION_MIN_REQUIRED #elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
@property (readonly, nonatomic, retain) NSImage *responseImage; @property (readonly, nonatomic, strong) NSImage *responseImage;
#endif #endif
#if __IPHONE_OS_VERSION_MIN_REQUIRED #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
/** /**
The scale factor used when interpreting the image data to construct `responseImage`. Specifying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the size property. This is set to the value of `[[UIScreen mainScreen] scale]` by default, which automatically scales images for retina displays, for instance. The scale factor used when interpreting the image data to construct `responseImage`. Specifying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the size property. This is set to the value of scale of the main screen by default, which automatically scales images for retina displays, for instance.
*/ */
@property (nonatomic, assign) CGFloat imageScale; @property (nonatomic, assign) CGFloat imageScale;
/**
Whether to automatically inflate response image data for compressed formats (such as PNG or JPEG). Enabling this can significantly improve drawing performance on iOS when used with `setCompletionBlockWithSuccess:failure:`, as it allows a bitmap representation to be constructed in the background rather than on the main thread. `YES` by default.
*/
@property (nonatomic, assign) BOOL automaticallyInflatesResponseImage;
#endif #endif
/**
An image constructed from the response data. If an error occurs during the request, `nil` will be returned, and the `error` property will be set to the error.
*/
/** /**
Creates and returns an `AFImageRequestOperation` object and sets the specified success callback. Creates and returns an `AFImageRequestOperation` object and sets the specified success callback.
@param urlRequest The request object to be loaded asynchronously during execution of the operation. @param urlRequest The request object to be loaded asynchronously during execution of the operation.
@param success A block object to be executed when the request finishes successfully. This block has no return value and takes a single arguments, the image created from the response data of the request. @param success A block object to be executed when the request finishes successfully. This block has no return value and takes a single argument, the image created from the response data of the request.
@return A new image request operation @return A new image request operation
*/ */
#if __IPHONE_OS_VERSION_MIN_REQUIRED #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
+ (AFImageRequestOperation *)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + (instancetype)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest
success:(void (^)(UIImage *image))success; success:(void (^)(UIImage *image))success;
#elif __MAC_OS_X_VERSION_MIN_REQUIRED #elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+ (AFImageRequestOperation *)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + (instancetype)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest
success:(void (^)(NSImage *image))success; success:(void (^)(NSImage *image))success;
#endif #endif
/** /**
Creates and returns an `AFImageRequestOperation` object and sets the specified success callback. Creates and returns an `AFImageRequestOperation` object and sets the specified success callback.
@param urlRequest The request object to be loaded asynchronously during execution of the operation. @param urlRequest The request object to be loaded asynchronously during execution of the operation.
@param imageProcessingBlock A block object to be executed after the image request finishes successfully, but before the image is returned in the `success` block. This block takes a single argument, the image loaded from the response body, and returns the processed image. @param imageProcessingBlock A block object to be executed after the image request finishes successfully, but before the image is returned in the `success` block. This block takes a single argument, the image loaded from the response body, and returns the processed image.
@param success A block object to be executed when the request finishes successfully, with a status code in the 2xx range, and with an acceptable content type (e.g. `image/png`). This block has no return value and takes three arguments: the request object of the operation, the response for the request, and the image created from the response data. @param success A block object to be executed when the request finishes successfully, with a status code in the 2xx range, and with an acceptable content type (e.g. `image/png`). This block has no return value and takes three arguments: the request object of the operation, the response for the request, and the image created from the response data.
@param failure A block object to be executed when the request finishes unsuccessfully. This block has no return value and takes three arguments: the request object of the operation, the response for the request, and the error associated with the cause for the unsuccessful operation. @param failure A block object to be executed when the request finishes unsuccessfully. This block has no return value and takes three arguments: the request object of the operation, the response for the request, and the error associated with the cause for the unsuccessful operation.
@return A new image request operation @return A new image request operation
*/ */
#if __IPHONE_OS_VERSION_MIN_REQUIRED #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
+ (AFImageRequestOperation *)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + (instancetype)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest
imageProcessingBlock:(UIImage *(^)(UIImage *image))imageProcessingBlock imageProcessingBlock:(UIImage *(^)(UIImage *image))imageProcessingBlock
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success
failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure; failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure;
#elif __MAC_OS_X_VERSION_MIN_REQUIRED #elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+ (AFImageRequestOperation *)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + (instancetype)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest
imageProcessingBlock:(NSImage *(^)(NSImage *image))imageProcessingBlock imageProcessingBlock:(NSImage *(^)(NSImage *image))imageProcessingBlock
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSImage *image))success success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSImage *image))success
failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure; failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure;
#endif #endif
@end @end

227
clients/ios/AFNetworking/AFImageRequestOperation.m Normal file → Executable file
View file

@ -1,17 +1,17 @@
// AFImageRequestOperation.m // AFImageRequestOperation.m
// //
// Copyright (c) 2011 Gowalla (http://gowalla.com/) // Copyright (c) 2011 Gowalla (http://gowalla.com/)
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights // in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is // copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions: // furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -22,32 +22,117 @@
#import "AFImageRequestOperation.h" #import "AFImageRequestOperation.h"
static dispatch_queue_t af_image_request_operation_processing_queue;
static dispatch_queue_t image_request_operation_processing_queue() { static dispatch_queue_t image_request_operation_processing_queue() {
if (af_image_request_operation_processing_queue == NULL) { static dispatch_queue_t af_image_request_operation_processing_queue;
af_image_request_operation_processing_queue = dispatch_queue_create("com.alamofire.networking.image-request.processing", 0); static dispatch_once_t onceToken;
} dispatch_once(&onceToken, ^{
af_image_request_operation_processing_queue = dispatch_queue_create("com.alamofire.networking.image-request.processing", DISPATCH_QUEUE_CONCURRENT);
});
return af_image_request_operation_processing_queue; return af_image_request_operation_processing_queue;
} }
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#import <CoreGraphics/CoreGraphics.h>
static UIImage * AFImageWithDataAtScale(NSData *data, CGFloat scale) {
if ([UIImage instancesRespondToSelector:@selector(initWithData:scale:)]) {
return [[UIImage alloc] initWithData:data scale:scale];
} else {
UIImage *image = [[UIImage alloc] initWithData:data];
return [[UIImage alloc] initWithCGImage:[image CGImage] scale:scale orientation:image.imageOrientation];
}
}
static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *response, NSData *data, CGFloat scale) {
if (!data || [data length] == 0) {
return nil;
}
CGImageRef imageRef = nil;
CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
if ([response.MIMEType isEqualToString:@"image/png"]) {
imageRef = CGImageCreateWithPNGDataProvider(dataProvider, NULL, true, kCGRenderingIntentDefault);
} else if ([response.MIMEType isEqualToString:@"image/jpeg"]) {
imageRef = CGImageCreateWithJPEGDataProvider(dataProvider, NULL, true, kCGRenderingIntentDefault);
}
if (!imageRef) {
UIImage *image = AFImageWithDataAtScale(data, scale);
if (image.images) {
CGDataProviderRelease(dataProvider);
return image;
}
imageRef = CGImageCreateCopy([image CGImage]);
}
CGDataProviderRelease(dataProvider);
if (!imageRef) {
return nil;
}
size_t width = CGImageGetWidth(imageRef);
size_t height = CGImageGetHeight(imageRef);
size_t bitsPerComponent = CGImageGetBitsPerComponent(imageRef);
size_t bytesPerRow = 0; // CGImageGetBytesPerRow() calculates incorrectly in iOS 5.0, so defer to CGBitmapContextCreate()
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
if (CGColorSpaceGetNumberOfComponents(colorSpace) == 3) {
int alpha = (bitmapInfo & kCGBitmapAlphaInfoMask);
if (alpha == kCGImageAlphaNone) {
bitmapInfo &= ~kCGBitmapAlphaInfoMask;
bitmapInfo |= kCGImageAlphaNoneSkipFirst;
} else if (!(alpha == kCGImageAlphaNoneSkipFirst || alpha == kCGImageAlphaNoneSkipLast)) {
bitmapInfo &= ~kCGBitmapAlphaInfoMask;
bitmapInfo |= kCGImageAlphaPremultipliedFirst;
}
}
CGContextRef context = CGBitmapContextCreate(NULL, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo);
CGColorSpaceRelease(colorSpace);
if (!context) {
CGImageRelease(imageRef);
return [[UIImage alloc] initWithData:data];
}
CGRect rect = CGRectMake(0.0f, 0.0f, width, height);
CGContextDrawImage(context, rect, imageRef);
CGImageRef inflatedImageRef = CGBitmapContextCreateImage(context);
CGContextRelease(context);
UIImage *inflatedImage = [[UIImage alloc] initWithCGImage:inflatedImageRef scale:scale orientation:UIImageOrientationUp];
CGImageRelease(inflatedImageRef);
CGImageRelease(imageRef);
return inflatedImage;
}
#endif
@interface AFImageRequestOperation () @interface AFImageRequestOperation ()
#if __IPHONE_OS_VERSION_MIN_REQUIRED #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
@property (readwrite, nonatomic, retain) UIImage *responseImage; @property (readwrite, nonatomic, strong) UIImage *responseImage;
#elif __MAC_OS_X_VERSION_MIN_REQUIRED #elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
@property (readwrite, nonatomic, retain) NSImage *responseImage; @property (readwrite, nonatomic, strong) NSImage *responseImage;
#endif #endif
@end @end
@implementation AFImageRequestOperation @implementation AFImageRequestOperation
@synthesize responseImage = _responseImage; @synthesize responseImage = _responseImage;
#if __IPHONE_OS_VERSION_MIN_REQUIRED #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
@synthesize imageScale = _imageScale; @synthesize imageScale = _imageScale;
#endif #endif
#if __IPHONE_OS_VERSION_MIN_REQUIRED #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
+ (AFImageRequestOperation *)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + (instancetype)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest
success:(void (^)(UIImage *image))success success:(void (^)(UIImage *image))success
{ {
return [self imageRequestOperationWithRequest:urlRequest imageProcessingBlock:nil success:^(NSURLRequest __unused *request, NSHTTPURLResponse __unused *response, UIImage *image) { return [self imageRequestOperationWithRequest:urlRequest imageProcessingBlock:nil success:^(NSURLRequest __unused *request, NSHTTPURLResponse __unused *response, UIImage *image) {
if (success) { if (success) {
@ -55,9 +140,9 @@ static dispatch_queue_t image_request_operation_processing_queue() {
} }
} failure:nil]; } failure:nil];
} }
#elif __MAC_OS_X_VERSION_MIN_REQUIRED #elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+ (AFImageRequestOperation *)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + (instancetype)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest
success:(void (^)(NSImage *image))success success:(void (^)(NSImage *image))success
{ {
return [self imageRequestOperationWithRequest:urlRequest imageProcessingBlock:nil success:^(NSURLRequest __unused *request, NSHTTPURLResponse __unused *response, NSImage *image) { return [self imageRequestOperationWithRequest:urlRequest imageProcessingBlock:nil success:^(NSURLRequest __unused *request, NSHTTPURLResponse __unused *response, NSImage *image) {
if (success) { if (success) {
@ -68,23 +153,25 @@ static dispatch_queue_t image_request_operation_processing_queue() {
#endif #endif
#if __IPHONE_OS_VERSION_MIN_REQUIRED #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
+ (AFImageRequestOperation *)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + (instancetype)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest
imageProcessingBlock:(UIImage *(^)(UIImage *))imageProcessingBlock imageProcessingBlock:(UIImage *(^)(UIImage *))imageProcessingBlock
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success
failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure
{ {
AFImageRequestOperation *requestOperation = [[[AFImageRequestOperation alloc] initWithRequest:urlRequest] autorelease]; AFImageRequestOperation *requestOperation = [(AFImageRequestOperation *)[self alloc] initWithRequest:urlRequest];
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if (success) { if (success) {
UIImage *image = responseObject; UIImage *image = responseObject;
if (imageProcessingBlock) { if (imageProcessingBlock) {
dispatch_async(image_request_operation_processing_queue(), ^(void) { dispatch_async(image_request_operation_processing_queue(), ^(void) {
UIImage *processedImage = imageProcessingBlock(image); UIImage *processedImage = imageProcessingBlock(image);
#pragma clang diagnostic push
dispatch_async(requestOperation.successCallbackQueue ? requestOperation.successCallbackQueue : dispatch_get_main_queue(), ^(void) { #pragma clang diagnostic ignored "-Wgnu"
dispatch_async(operation.successCallbackQueue ?: dispatch_get_main_queue(), ^(void) {
success(operation.request, operation.response, processedImage); success(operation.request, operation.response, processedImage);
}); });
#pragma clang diagnostic pop
}); });
} else { } else {
success(operation.request, operation.response, image); success(operation.request, operation.response, image);
@ -95,17 +182,17 @@ static dispatch_queue_t image_request_operation_processing_queue() {
failure(operation.request, operation.response, error); failure(operation.request, operation.response, error);
} }
}]; }];
return requestOperation; return requestOperation;
} }
#elif __MAC_OS_X_VERSION_MIN_REQUIRED #elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+ (AFImageRequestOperation *)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + (instancetype)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest
imageProcessingBlock:(NSImage *(^)(NSImage *))imageProcessingBlock imageProcessingBlock:(NSImage *(^)(NSImage *))imageProcessingBlock
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSImage *image))success success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSImage *image))success
failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure
{ {
AFImageRequestOperation *requestOperation = [[[AFImageRequestOperation alloc] initWithRequest:urlRequest] autorelease]; AFImageRequestOperation *requestOperation = [(AFImageRequestOperation *)[self alloc] initWithRequest:urlRequest];
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if (success) { if (success) {
NSImage *image = responseObject; NSImage *image = responseObject;
@ -113,7 +200,7 @@ static dispatch_queue_t image_request_operation_processing_queue() {
dispatch_async(image_request_operation_processing_queue(), ^(void) { dispatch_async(image_request_operation_processing_queue(), ^(void) {
NSImage *processedImage = imageProcessingBlock(image); NSImage *processedImage = imageProcessingBlock(image);
dispatch_async(requestOperation.successCallbackQueue ? requestOperation.successCallbackQueue : dispatch_get_main_queue(), ^(void) { dispatch_async(operation.successCallbackQueue ?: dispatch_get_main_queue(), ^(void) {
success(operation.request, operation.response, processedImage); success(operation.request, operation.response, processedImage);
}); });
}); });
@ -126,7 +213,7 @@ static dispatch_queue_t image_request_operation_processing_queue() {
failure(operation.request, operation.response, error); failure(operation.request, operation.response, error);
} }
}]; }];
return requestOperation; return requestOperation;
} }
#endif #endif
@ -136,54 +223,55 @@ static dispatch_queue_t image_request_operation_processing_queue() {
if (!self) { if (!self) {
return nil; return nil;
} }
#if __IPHONE_OS_VERSION_MIN_REQUIRED #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
self.imageScale = [[UIScreen mainScreen] scale]; self.imageScale = [[UIScreen mainScreen] scale];
self.automaticallyInflatesResponseImage = YES;
#endif #endif
return self; return self;
} }
- (void)dealloc {
[_responseImage release];
[super dealloc];
}
#if __IPHONE_OS_VERSION_MIN_REQUIRED #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
- (UIImage *)responseImage { - (UIImage *)responseImage {
if (!_responseImage && [self.responseData length] > 0 && [self isFinished]) { if (!_responseImage && [self.responseData length] > 0 && [self isFinished]) {
UIImage *image = [UIImage imageWithData:self.responseData]; if (self.automaticallyInflatesResponseImage) {
self.responseImage = AFInflatedImageFromResponseWithDataAtScale(self.response, self.responseData, self.imageScale);
self.responseImage = [UIImage imageWithCGImage:[image CGImage] scale:self.imageScale orientation:image.imageOrientation]; } else {
self.responseImage = AFImageWithDataAtScale(self.responseData, self.imageScale);
}
} }
return _responseImage; return _responseImage;
} }
- (void)setImageScale:(CGFloat)imageScale { - (void)setImageScale:(CGFloat)imageScale {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wfloat-equal"
if (imageScale == _imageScale) { if (imageScale == _imageScale) {
return; return;
} }
#pragma clang diagnostic pop
_imageScale = imageScale; _imageScale = imageScale;
self.responseImage = nil; self.responseImage = nil;
} }
#elif __MAC_OS_X_VERSION_MIN_REQUIRED #elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
- (NSImage *)responseImage { - (NSImage *)responseImage {
if (!_responseImage && [self.responseData length] > 0 && [self isFinished]) { if (!_responseImage && [self.responseData length] > 0 && [self isFinished]) {
// Ensure that the image is set to it's correct pixel width and height // Ensure that the image is set to it's correct pixel width and height
NSBitmapImageRep *bitimage = [[NSBitmapImageRep alloc] initWithData:self.responseData]; NSBitmapImageRep *bitimage = [[NSBitmapImageRep alloc] initWithData:self.responseData];
self.responseImage = [[[NSImage alloc] initWithSize:NSMakeSize([bitimage pixelsWide], [bitimage pixelsHigh])] autorelease]; self.responseImage = [[NSImage alloc] initWithSize:NSMakeSize([bitimage pixelsWide], [bitimage pixelsHigh])];
[self.responseImage addRepresentation:bitimage]; [self.responseImage addRepresentation:bitimage];
[bitimage release];
} }
return _responseImage; return _responseImage;
} }
#endif #endif
#pragma mark - AFHTTPClientOperation #pragma mark - AFHTTPRequestOperation
+ (NSSet *)acceptableContentTypes { + (NSSet *)acceptableContentTypes {
return [NSSet setWithObjects:@"image/tiff", @"image/jpeg", @"image/gif", @"image/png", @"image/ico", @"image/x-icon", @"image/bmp", @"image/x-bmp", @"image/x-xbitmap", @"image/x-win-bitmap", nil]; return [NSSet setWithObjects:@"image/tiff", @"image/jpeg", @"image/gif", @"image/png", @"image/ico", @"image/x-icon", @"image/bmp", @"image/x-bmp", @"image/x-xbitmap", @"image/x-win-bitmap", nil];
@ -195,42 +283,43 @@ static dispatch_queue_t image_request_operation_processing_queue() {
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{
_acceptablePathExtension = [[NSSet alloc] initWithObjects:@"tif", @"tiff", @"jpg", @"jpeg", @"gif", @"png", @"ico", @"bmp", @"cur", nil]; _acceptablePathExtension = [[NSSet alloc] initWithObjects:@"tif", @"tiff", @"jpg", @"jpeg", @"gif", @"png", @"ico", @"bmp", @"cur", nil];
}); });
return [_acceptablePathExtension containsObject:[[request URL] pathExtension]] || [super canProcessRequest:request]; return [_acceptablePathExtension containsObject:[[request URL] pathExtension]] || [super canProcessRequest:request];
} }
- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success - (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{ {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
#pragma clang diagnostic ignored "-Wgnu"
self.completionBlock = ^ { self.completionBlock = ^ {
if ([self isCancelled]) {
return;
}
dispatch_async(image_request_operation_processing_queue(), ^(void) { dispatch_async(image_request_operation_processing_queue(), ^(void) {
if (self.error) { if (self.error) {
if (failure) { if (failure) {
dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ dispatch_async(self.failureCallbackQueue ?: dispatch_get_main_queue(), ^{
failure(self, self.error); failure(self, self.error);
}); });
} }
} else { } else {
if (success) { if (success) {
#if __IPHONE_OS_VERSION_MIN_REQUIRED #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
UIImage *image = nil; UIImage *image = nil;
#elif __MAC_OS_X_VERSION_MIN_REQUIRED #elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
NSImage *image = nil; NSImage *image = nil;
#endif #endif
image = self.responseImage; image = self.responseImage;
dispatch_async(self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ dispatch_async(self.successCallbackQueue ?: dispatch_get_main_queue(), ^{
success(self, image); success(self, image);
}); });
} }
} }
}); });
}; };
#pragma clang diagnostic pop
} }
@end @end

17
clients/ios/AFNetworking/AFJSONRequestOperation.h Normal file → Executable file
View file

@ -33,7 +33,7 @@
- `application/json` - `application/json`
- `text/json` - `text/json`
@warning JSON parsing will automatically use JSONKit, SBJSON, YAJL, or NextiveJSON, if provided. Otherwise, the built-in `NSJSONSerialization` class is used, if available (iOS 5.0 and Mac OS 10.7). If the build target does not either support `NSJSONSerialization` or include a third-party JSON library, a runtime exception will be thrown when attempting to parse a JSON request. @warning JSON parsing will use the built-in `NSJSONSerialization` class.
*/ */
@interface AFJSONRequestOperation : AFHTTPRequestOperation @interface AFJSONRequestOperation : AFHTTPRequestOperation
@ -44,8 +44,13 @@
/** /**
A JSON object constructed from the response data. If an error occurs while parsing, `nil` will be returned, and the `error` property will be set to the error. A JSON object constructed from the response data. If an error occurs while parsing, `nil` will be returned, and the `error` property will be set to the error.
*/ */
@property (readonly, nonatomic, retain) id responseJSON; @property (readonly, nonatomic, strong) id responseJSON;
/**
Options for reading the response JSON data and creating the Foundation objects. For possible values, see the `NSJSONSerialization` documentation section "NSJSONReadingOptions".
*/
@property (nonatomic, assign) NSJSONReadingOptions JSONReadingOptions;
///---------------------------------- ///----------------------------------
/// @name Creating Request Operations /// @name Creating Request Operations
///---------------------------------- ///----------------------------------
@ -55,12 +60,12 @@
@param urlRequest The request object to be loaded asynchronously during execution of the operation @param urlRequest The request object to be loaded asynchronously during execution of the operation
@param success A block object to be executed when the operation finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the JSON object created from the response data of request. @param success A block object to be executed when the operation finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the JSON object created from the response data of request.
@param failure A block object to be executed when the operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data as JSON. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error describing the network or parsing error that occurred. @param failure A block object to be executed when the operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data as JSON. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error describing the network or parsing error that occurred.
@return A new JSON request operation @return A new JSON request operation
*/ */
+ (AFJSONRequestOperation *)JSONRequestOperationWithRequest:(NSURLRequest *)urlRequest + (instancetype)JSONRequestOperationWithRequest:(NSURLRequest *)urlRequest
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id JSON))success success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id JSON))success
failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON))failure; failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON))failure;
@end @end

88
clients/ios/AFNetworking/AFJSONRequestOperation.m Normal file → Executable file
View file

@ -1,17 +1,17 @@
// AFJSONRequestOperation.m // AFJSONRequestOperation.m
// //
// Copyright (c) 2011 Gowalla (http://gowalla.com/) // Copyright (c) 2011 Gowalla (http://gowalla.com/)
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights // in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is // copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions: // furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -21,31 +21,34 @@
// THE SOFTWARE. // THE SOFTWARE.
#import "AFJSONRequestOperation.h" #import "AFJSONRequestOperation.h"
#import "AFJSONUtilities.h"
static dispatch_queue_t af_json_request_operation_processing_queue;
static dispatch_queue_t json_request_operation_processing_queue() { static dispatch_queue_t json_request_operation_processing_queue() {
if (af_json_request_operation_processing_queue == NULL) { static dispatch_queue_t af_json_request_operation_processing_queue;
af_json_request_operation_processing_queue = dispatch_queue_create("com.alamofire.networking.json-request.processing", 0); static dispatch_once_t onceToken;
} dispatch_once(&onceToken, ^{
af_json_request_operation_processing_queue = dispatch_queue_create("com.alamofire.networking.json-request.processing", DISPATCH_QUEUE_CONCURRENT);
});
return af_json_request_operation_processing_queue; return af_json_request_operation_processing_queue;
} }
@interface AFJSONRequestOperation () @interface AFJSONRequestOperation ()
@property (readwrite, nonatomic, retain) id responseJSON; @property (readwrite, nonatomic, strong) id responseJSON;
@property (readwrite, nonatomic, retain) NSError *JSONError; @property (readwrite, nonatomic, strong) NSError *JSONError;
@property (readwrite, nonatomic, strong) NSRecursiveLock *lock;
@end @end
@implementation AFJSONRequestOperation @implementation AFJSONRequestOperation
@synthesize responseJSON = _responseJSON; @synthesize responseJSON = _responseJSON;
@synthesize JSONReadingOptions = _JSONReadingOptions;
@synthesize JSONError = _JSONError; @synthesize JSONError = _JSONError;
@dynamic lock;
+ (AFJSONRequestOperation *)JSONRequestOperationWithRequest:(NSURLRequest *)urlRequest + (instancetype)JSONRequestOperationWithRequest:(NSURLRequest *)urlRequest
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id JSON))success success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id JSON))success
failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON))failure failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON))failure
{ {
AFJSONRequestOperation *requestOperation = [[[self alloc] initWithRequest:urlRequest] autorelease]; AFJSONRequestOperation *requestOperation = [(AFJSONRequestOperation *)[self alloc] initWithRequest:urlRequest];
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if (success) { if (success) {
success(operation.request, operation.response, responseObject); success(operation.request, operation.response, responseObject);
@ -55,29 +58,37 @@ static dispatch_queue_t json_request_operation_processing_queue() {
failure(operation.request, operation.response, error, [(AFJSONRequestOperation *)operation responseJSON]); failure(operation.request, operation.response, error, [(AFJSONRequestOperation *)operation responseJSON]);
} }
}]; }];
return requestOperation; return requestOperation;
} }
- (void)dealloc {
[_responseJSON release];
[_JSONError release];
[super dealloc];
}
- (id)responseJSON { - (id)responseJSON {
[self.lock lock];
if (!_responseJSON && [self.responseData length] > 0 && [self isFinished] && !self.JSONError) { if (!_responseJSON && [self.responseData length] > 0 && [self isFinished] && !self.JSONError) {
NSError *error = nil; NSError *error = nil;
if ([self.responseData length] == 0) { // Workaround for behavior of Rails to return a single space for `head :ok` (a workaround for a bug in Safari), which is not interpreted as valid input by NSJSONSerialization.
self.responseJSON = nil; // See https://github.com/rails/rails/issues/1742
} else { if (self.responseString && ![self.responseString isEqualToString:@" "]) {
self.responseJSON = AFJSONDecode(self.responseData, &error); // Workaround for a bug in NSJSONSerialization when Unicode character escape codes are used instead of the actual character
// See http://stackoverflow.com/a/12843465/157142
NSData *data = [self.responseString dataUsingEncoding:NSUTF8StringEncoding];
if (data) {
self.responseJSON = [NSJSONSerialization JSONObjectWithData:data options:self.JSONReadingOptions error:&error];
} else {
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
[userInfo setValue:@"Operation responseData failed decoding as a UTF-8 string" forKey:NSLocalizedDescriptionKey];
[userInfo setValue:[NSString stringWithFormat:@"Could not decode string: %@", self.responseString] forKey:NSLocalizedFailureReasonErrorKey];
error = [[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:userInfo];
}
} }
self.JSONError = error; self.JSONError = error;
} }
[self.lock unlock];
return _responseJSON; return _responseJSON;
} }
@ -102,37 +113,38 @@ static dispatch_queue_t json_request_operation_processing_queue() {
- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success - (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{ {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
#pragma clang diagnostic ignored "-Wgnu"
self.completionBlock = ^ { self.completionBlock = ^ {
if ([self isCancelled]) {
return;
}
if (self.error) { if (self.error) {
if (failure) { if (failure) {
dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ dispatch_async(self.failureCallbackQueue ?: dispatch_get_main_queue(), ^{
failure(self, self.error); failure(self, self.error);
}); });
} }
} else { } else {
dispatch_async(json_request_operation_processing_queue(), ^{ dispatch_async(json_request_operation_processing_queue(), ^{
id JSON = self.responseJSON; id JSON = self.responseJSON;
if (self.JSONError) { if (self.error) {
if (failure) { if (failure) {
dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ dispatch_async(self.failureCallbackQueue ?: dispatch_get_main_queue(), ^{
failure(self, self.error); failure(self, self.error);
}); });
} }
} else { } else {
if (success) { if (success) {
dispatch_async(self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ dispatch_async(self.successCallbackQueue ?: dispatch_get_main_queue(), ^{
success(self, JSON); success(self, JSON);
}); });
} }
} }
}); });
} }
}; };
#pragma clang diagnostic pop
} }
@end @end

View file

@ -1,17 +1,17 @@
// AFNetworkActivityIndicatorManager.h // AFNetworkActivityIndicatorManager.h
// //
// Copyright (c) 2011 Gowalla (http://gowalla.com/) // Copyright (c) 2011 Gowalla (http://gowalla.com/)
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights // in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is // copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions: // furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -24,34 +24,41 @@
#import <Availability.h> #import <Availability.h>
#if __IPHONE_OS_VERSION_MIN_REQUIRED #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
/** /**
`AFNetworkActivityIndicatorManager` manages the state of the network activity indicator in the status bar. When enabled, it will listen for notifications indicating that a network request operation has started or finished, and start or stop animating the indicator accordingly. The number of active requests is incremented and decremented much like a stack or a semaphore, and the activity indicator will animate so long as that number is greater than zero. `AFNetworkActivityIndicatorManager` manages the state of the network activity indicator in the status bar. When enabled, it will listen for notifications indicating that a network request operation has started or finished, and start or stop animating the indicator accordingly. The number of active requests is incremented and decremented much like a stack or a semaphore, and the activity indicator will animate so long as that number is greater than zero.
@discussion By setting `isNetworkActivityIndicatorVisible` to `YES` for `sharedManager`, the network activity indicator will show and hide automatically as requests start and finish. You should not ever need to call `incrementActivityCount` or `decrementActivityCount` yourself. You should enable the shared instance of `AFNetworkActivityIndicatorManager` when your application finishes launching. In `AppDelegate application:didFinishLaunchingWithOptions:` you can do so with the following code:
[[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES];
By setting `isNetworkActivityIndicatorVisible` to `YES` for `sharedManager`, the network activity indicator will show and hide automatically as requests start and finish. You should not ever need to call `incrementActivityCount` or `decrementActivityCount` yourself.
See the Apple Human Interface Guidelines section about the Network Activity Indicator for more information:
http://developer.apple.com/library/iOS/#documentation/UserExperience/Conceptual/MobileHIG/UIElementGuidelines/UIElementGuidelines.html#//apple_ref/doc/uid/TP40006556-CH13-SW44
*/ */
@interface AFNetworkActivityIndicatorManager : NSObject @interface AFNetworkActivityIndicatorManager : NSObject
/** /**
A Boolean value indicating whether the manager is enabled. A Boolean value indicating whether the manager is enabled.
@discussion If YES, the manager will change status bar network activity indicator according to network operation notifications it receives. The default value is NO. If YES, the manager will change status bar network activity indicator according to network operation notifications it receives. The default value is NO.
*/ */
@property (nonatomic, assign, getter = isEnabled) BOOL enabled; @property (nonatomic, assign, getter = isEnabled) BOOL enabled;
/** /**
A Boolean value indicating whether the network activity indicator is currently displayed in the status bar. A Boolean value indicating whether the network activity indicator is currently displayed in the status bar.
*/ */
@property (readonly, nonatomic, assign) BOOL isNetworkActivityIndicatorVisible; @property (readonly, nonatomic, assign) BOOL isNetworkActivityIndicatorVisible;
/** /**
Returns the shared network activity indicator manager object for the system. Returns the shared network activity indicator manager object for the system.
@return The systemwide network activity indicator manager. @return The systemwide network activity indicator manager.
*/ */
+ (AFNetworkActivityIndicatorManager *)sharedManager; + (instancetype)sharedManager;
/** /**
Increments the number of active network requests. If this number was zero before incrementing, this will start animating the status bar network activity indicator. Increments the number of active network requests. If this number was zero before incrementing, this will start animating the status bar network activity indicator.

View file

@ -1,17 +1,17 @@
// AFNetworkActivityIndicatorManager.m // AFNetworkActivityIndicatorManager.m
// //
// Copyright (c) 2011 Gowalla (http://gowalla.com/) // Copyright (c) 2011 Gowalla (http://gowalla.com/)
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights // in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is // copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions: // furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -24,15 +24,16 @@
#import "AFHTTPRequestOperation.h" #import "AFHTTPRequestOperation.h"
#if __IPHONE_OS_VERSION_MIN_REQUIRED #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
static NSTimeInterval const kAFNetworkActivityIndicatorInvisibilityDelay = 0.25; static NSTimeInterval const kAFNetworkActivityIndicatorInvisibilityDelay = 0.17;
@interface AFNetworkActivityIndicatorManager () @interface AFNetworkActivityIndicatorManager ()
@property (readwrite, atomic, assign) NSInteger activityCount; @property (readwrite, nonatomic, assign) NSInteger activityCount;
@property (readwrite, nonatomic, retain) NSTimer *activityIndicatorVisibilityTimer; @property (readwrite, nonatomic, strong) NSTimer *activityIndicatorVisibilityTimer;
@property (readonly, getter = isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible; @property (readonly, nonatomic, getter = isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible;
- (void)updateNetworkActivityIndicatorVisibility; - (void)updateNetworkActivityIndicatorVisibility;
- (void)updateNetworkActivityIndicatorVisibilityDelayed;
@end @end
@implementation AFNetworkActivityIndicatorManager @implementation AFNetworkActivityIndicatorManager
@ -41,35 +42,37 @@ static NSTimeInterval const kAFNetworkActivityIndicatorInvisibilityDelay = 0.25;
@synthesize enabled = _enabled; @synthesize enabled = _enabled;
@dynamic networkActivityIndicatorVisible; @dynamic networkActivityIndicatorVisible;
+ (AFNetworkActivityIndicatorManager *)sharedManager { + (instancetype)sharedManager {
static AFNetworkActivityIndicatorManager *_sharedManager = nil; static AFNetworkActivityIndicatorManager *_sharedManager = nil;
static dispatch_once_t oncePredicate; static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{ dispatch_once(&oncePredicate, ^{
_sharedManager = [[self alloc] init]; _sharedManager = [[self alloc] init];
}); });
return _sharedManager; return _sharedManager;
} }
+ (NSSet *)keyPathsForValuesAffectingIsNetworkActivityIndicatorVisible {
return [NSSet setWithObject:@"activityCount"];
}
- (id)init { - (id)init {
self = [super init]; self = [super init];
if (!self) { if (!self) {
return nil; return nil;
} }
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(incrementActivityCount) name:AFNetworkingOperationDidStartNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkingOperationDidStart:) name:AFNetworkingOperationDidStartNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(decrementActivityCount) name:AFNetworkingOperationDidFinishNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkingOperationDidFinish:) name:AFNetworkingOperationDidFinishNotification object:nil];
return self; return self;
} }
- (void)dealloc { - (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self]; [[NSNotificationCenter defaultCenter] removeObserver:self];
[_activityIndicatorVisibilityTimer invalidate]; [_activityIndicatorVisibilityTimer invalidate];
[_activityIndicatorVisibilityTimer release]; _activityIndicatorVisibilityTimer = nil;
[super dealloc];
} }
- (void)updateNetworkActivityIndicatorVisibilityDelayed { - (void)updateNetworkActivityIndicatorVisibilityDelayed {
@ -78,9 +81,9 @@ static NSTimeInterval const kAFNetworkActivityIndicatorInvisibilityDelay = 0.25;
if (![self isNetworkActivityIndicatorVisible]) { if (![self isNetworkActivityIndicatorVisible]) {
[self.activityIndicatorVisibilityTimer invalidate]; [self.activityIndicatorVisibilityTimer invalidate];
self.activityIndicatorVisibilityTimer = [NSTimer timerWithTimeInterval:kAFNetworkActivityIndicatorInvisibilityDelay target:self selector:@selector(updateNetworkActivityIndicatorVisibility) userInfo:nil repeats:NO]; self.activityIndicatorVisibilityTimer = [NSTimer timerWithTimeInterval:kAFNetworkActivityIndicatorInvisibilityDelay target:self selector:@selector(updateNetworkActivityIndicatorVisibility) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:self.activityIndicatorVisibilityTimer forMode:NSRunLoopCommonModes]; [[NSRunLoop mainRunLoop] addTimer:self.activityIndicatorVisibilityTimer forMode:NSRunLoopCommonModes];
} else { } else {
[self updateNetworkActivityIndicatorVisibility]; [self performSelectorOnMainThread:@selector(updateNetworkActivityIndicatorVisibility) withObject:nil waitUntilDone:NO modes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
} }
} }
} }
@ -90,9 +93,7 @@ static NSTimeInterval const kAFNetworkActivityIndicatorInvisibilityDelay = 0.25;
} }
- (void)updateNetworkActivityIndicatorVisibility { - (void)updateNetworkActivityIndicatorVisibility {
dispatch_async(dispatch_get_main_queue(), ^{ [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:[self isNetworkActivityIndicatorVisible]];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:[self isNetworkActivityIndicatorVisible]];
});
} }
// Not exposed, but used if activityCount is set via KVC. // Not exposed, but used if activityCount is set via KVC.
@ -104,7 +105,10 @@ static NSTimeInterval const kAFNetworkActivityIndicatorInvisibilityDelay = 0.25;
@synchronized(self) { @synchronized(self) {
_activityCount = activityCount; _activityCount = activityCount;
} }
[self updateNetworkActivityIndicatorVisibilityDelayed];
dispatch_async(dispatch_get_main_queue(), ^{
[self updateNetworkActivityIndicatorVisibilityDelayed];
});
} }
- (void)incrementActivityCount { - (void)incrementActivityCount {
@ -113,20 +117,39 @@ static NSTimeInterval const kAFNetworkActivityIndicatorInvisibilityDelay = 0.25;
_activityCount++; _activityCount++;
} }
[self didChangeValueForKey:@"activityCount"]; [self didChangeValueForKey:@"activityCount"];
[self updateNetworkActivityIndicatorVisibilityDelayed];
dispatch_async(dispatch_get_main_queue(), ^{
[self updateNetworkActivityIndicatorVisibilityDelayed];
});
} }
- (void)decrementActivityCount { - (void)decrementActivityCount {
[self willChangeValueForKey:@"activityCount"]; [self willChangeValueForKey:@"activityCount"];
@synchronized(self) { @synchronized(self) {
_activityCount--; #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
_activityCount = MAX(_activityCount - 1, 0);
#pragma clang diagnostic pop
} }
[self didChangeValueForKey:@"activityCount"]; [self didChangeValueForKey:@"activityCount"];
[self updateNetworkActivityIndicatorVisibilityDelayed];
dispatch_async(dispatch_get_main_queue(), ^{
[self updateNetworkActivityIndicatorVisibilityDelayed];
});
} }
+ (NSSet *)keyPathsForValuesAffectingIsNetworkActivityIndicatorVisible { - (void)networkingOperationDidStart:(NSNotification *)notification {
return [NSSet setWithObject:@"activityCount"]; AFURLConnectionOperation *connectionOperation = [notification object];
if (connectionOperation.request.URL) {
[self incrementActivityCount];
}
}
- (void)networkingOperationDidFinish:(NSNotification *)notification {
AFURLConnectionOperation *connectionOperation = [notification object];
if (connectionOperation.request.URL) {
[self decrementActivityCount];
}
} }
@end @end

25
clients/ios/AFNetworking/AFNetworking.h Normal file → Executable file
View file

@ -24,21 +24,20 @@
#import <Availability.h> #import <Availability.h>
#ifndef _AFNETWORKING_ #ifndef _AFNETWORKING_
#define _AFNETWORKING_ #define _AFNETWORKING_
#import "AFURLConnectionOperation.h" #import "AFURLConnectionOperation.h"
#import "AFHTTPRequestOperation.h" #import "AFHTTPRequestOperation.h"
#import "AFJSONRequestOperation.h" #import "AFJSONRequestOperation.h"
#import "AFXMLRequestOperation.h" #import "AFXMLRequestOperation.h"
#import "AFPropertyListRequestOperation.h" #import "AFPropertyListRequestOperation.h"
#import "AFHTTPClient.h" #import "AFHTTPClient.h"
#import "AFImageRequestOperation.h" #import "AFImageRequestOperation.h"
#if __IPHONE_OS_VERSION_MIN_REQUIRED
#import "AFNetworkActivityIndicatorManager.h"
#import "UIImageView+AFNetworking.h"
#endif
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#import "AFNetworkActivityIndicatorManager.h"
#import "UIImageView+AFNetworking.h"
#endif
#endif /* _AFNETWORKING_ */ #endif /* _AFNETWORKING_ */

View file

@ -1,17 +1,17 @@
// AFPropertyListRequestOperation.h // AFPropertyListRequestOperation.h
// //
// Copyright (c) 2011 Gowalla (http://gowalla.com/) // Copyright (c) 2011 Gowalla (http://gowalla.com/)
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights // in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is // copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions: // furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -25,11 +25,11 @@
/** /**
`AFPropertyListRequestOperation` is a subclass of `AFHTTPRequestOperation` for downloading and deserializing objects with property list (plist) response data. `AFPropertyListRequestOperation` is a subclass of `AFHTTPRequestOperation` for downloading and deserializing objects with property list (plist) response data.
## Acceptable Content Types ## Acceptable Content Types
By default, `AFPropertyListRequestOperation` accepts the following MIME types: By default, `AFPropertyListRequestOperation` accepts the following MIME types:
- `application/x-plist` - `application/x-plist`
*/ */
@interface AFPropertyListRequestOperation : AFHTTPRequestOperation @interface AFPropertyListRequestOperation : AFHTTPRequestOperation
@ -41,7 +41,7 @@
/** /**
An object deserialized from a plist constructed using the response data. An object deserialized from a plist constructed using the response data.
*/ */
@property (readonly, nonatomic, retain) id responsePropertyList; @property (readonly, nonatomic) id responsePropertyList;
///-------------------------------------- ///--------------------------------------
/// @name Managing Property List Behavior /// @name Managing Property List Behavior
@ -54,15 +54,15 @@
/** /**
Creates and returns an `AFPropertyListRequestOperation` object and sets the specified success and failure callbacks. Creates and returns an `AFPropertyListRequestOperation` object and sets the specified success and failure callbacks.
@param urlRequest The request object to be loaded asynchronously during execution of the operation @param urlRequest The request object to be loaded asynchronously during execution of the operation
@param success A block object to be executed when the operation finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the object deserialized from a plist constructed using the response data. @param success A block object to be executed when the operation finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the object deserialized from a plist constructed using the response data.
@param failure A block object to be executed when the operation finishes unsuccessfully, or that finishes successfully, but encountered an error while deserializing the object from a property list. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error describing the network or parsing error that occurred. @param failure A block object to be executed when the operation finishes unsuccessfully, or that finishes successfully, but encountered an error while deserializing the object from a property list. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error describing the network or parsing error that occurred.
@return A new property list request operation @return A new property list request operation
*/ */
+ (AFPropertyListRequestOperation *)propertyListRequestOperationWithRequest:(NSURLRequest *)urlRequest + (instancetype)propertyListRequestOperationWithRequest:(NSURLRequest *)urlRequest
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id propertyList))success success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id propertyList))success
failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id propertyList))failure; failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id propertyList))failure;
@end @end

View file

@ -1,17 +1,17 @@
// AFPropertyListRequestOperation.m // AFPropertyListRequestOperation.m
// //
// Copyright (c) 2011 Gowalla (http://gowalla.com/) // Copyright (c) 2011 Gowalla (http://gowalla.com/)
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights // in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is // copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions: // furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -22,19 +22,20 @@
#import "AFPropertyListRequestOperation.h" #import "AFPropertyListRequestOperation.h"
static dispatch_queue_t af_property_list_request_operation_processing_queue;
static dispatch_queue_t property_list_request_operation_processing_queue() { static dispatch_queue_t property_list_request_operation_processing_queue() {
if (af_property_list_request_operation_processing_queue == NULL) { static dispatch_queue_t af_property_list_request_operation_processing_queue;
af_property_list_request_operation_processing_queue = dispatch_queue_create("com.alamofire.networking.property-list-request.processing", 0); static dispatch_once_t onceToken;
} dispatch_once(&onceToken, ^{
af_property_list_request_operation_processing_queue = dispatch_queue_create("com.alamofire.networking.property-list-request.processing", DISPATCH_QUEUE_CONCURRENT);
});
return af_property_list_request_operation_processing_queue; return af_property_list_request_operation_processing_queue;
} }
@interface AFPropertyListRequestOperation () @interface AFPropertyListRequestOperation ()
@property (readwrite, nonatomic, retain) id responsePropertyList; @property (readwrite, nonatomic) id responsePropertyList;
@property (readwrite, nonatomic, assign) NSPropertyListFormat propertyListFormat; @property (readwrite, nonatomic, assign) NSPropertyListFormat propertyListFormat;
@property (readwrite, nonatomic, retain) NSError *propertyListError; @property (readwrite, nonatomic) NSError *propertyListError;
@end @end
@implementation AFPropertyListRequestOperation @implementation AFPropertyListRequestOperation
@ -43,11 +44,11 @@ static dispatch_queue_t property_list_request_operation_processing_queue() {
@synthesize propertyListFormat = _propertyListFormat; @synthesize propertyListFormat = _propertyListFormat;
@synthesize propertyListError = _propertyListError; @synthesize propertyListError = _propertyListError;
+ (AFPropertyListRequestOperation *)propertyListRequestOperationWithRequest:(NSURLRequest *)request + (instancetype)propertyListRequestOperationWithRequest:(NSURLRequest *)request
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id propertyList))success success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id propertyList))success
failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id propertyList))failure failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id propertyList))failure
{ {
AFPropertyListRequestOperation *requestOperation = [[[self alloc] initWithRequest:request] autorelease]; AFPropertyListRequestOperation *requestOperation = [(AFPropertyListRequestOperation *)[self alloc] initWithRequest:request];
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if (success) { if (success) {
success(operation.request, operation.response, responseObject); success(operation.request, operation.response, responseObject);
@ -57,7 +58,7 @@ static dispatch_queue_t property_list_request_operation_processing_queue() {
failure(operation.request, operation.response, error, [(AFPropertyListRequestOperation *)operation responsePropertyList]); failure(operation.request, operation.response, error, [(AFPropertyListRequestOperation *)operation responsePropertyList]);
} }
}]; }];
return requestOperation; return requestOperation;
} }
@ -66,17 +67,12 @@ static dispatch_queue_t property_list_request_operation_processing_queue() {
if (!self) { if (!self) {
return nil; return nil;
} }
self.propertyListReadOptions = NSPropertyListImmutable; self.propertyListReadOptions = NSPropertyListImmutable;
return self; return self;
} }
- (void)dealloc {
[_responsePropertyList release];
[_propertyListError release];
[super dealloc];
}
- (id)responsePropertyList { - (id)responsePropertyList {
if (!_responsePropertyList && [self.responseData length] > 0 && [self isFinished]) { if (!_responsePropertyList && [self.responseData length] > 0 && [self isFinished]) {
@ -86,7 +82,7 @@ static dispatch_queue_t property_list_request_operation_processing_queue() {
self.propertyListFormat = format; self.propertyListFormat = format;
self.propertyListError = error; self.propertyListError = error;
} }
return _responsePropertyList; return _responsePropertyList;
} }
@ -111,37 +107,37 @@ static dispatch_queue_t property_list_request_operation_processing_queue() {
- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success - (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{ {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
#pragma clang diagnostic ignored "-Wgnu"
self.completionBlock = ^ { self.completionBlock = ^ {
if ([self isCancelled]) {
return;
}
if (self.error) { if (self.error) {
if (failure) { if (failure) {
dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ dispatch_async(self.failureCallbackQueue ?: dispatch_get_main_queue(), ^{
failure(self, self.error); failure(self, self.error);
}); });
} }
} else { } else {
dispatch_async(property_list_request_operation_processing_queue(), ^(void) { dispatch_async(property_list_request_operation_processing_queue(), ^(void) {
id propertyList = self.responsePropertyList; id propertyList = self.responsePropertyList;
if (self.propertyListError) { if (self.propertyListError) {
if (failure) { if (failure) {
dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ dispatch_async(self.failureCallbackQueue ?: dispatch_get_main_queue(), ^{
failure(self, self.error); failure(self, self.error);
}); });
} }
} else { } else {
if (success) { if (success) {
dispatch_async(self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ dispatch_async(self.successCallbackQueue ?: dispatch_get_main_queue(), ^{
success(self, propertyList); success(self, propertyList);
}); });
} }
} }
}); });
} }
}; };
#pragma clang diagnostic pop
} }
@end @end

554
clients/ios/AFNetworking/AFURLConnectionOperation.h Normal file → Executable file
View file

@ -1,17 +1,17 @@
// AFURLConnectionOperation.h // AFURLConnectionOperation.h
// //
// Copyright (c) 2011 Gowalla (http://gowalla.com/) // Copyright (c) 2011 Gowalla (http://gowalla.com/)
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights // in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is // copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions: // furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -22,12 +22,344 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import <Availability.h>
/** /**
Indicates an error occured in AFNetworking. `AFURLConnectionOperation` is a subclass of `NSOperation` that implements `NSURLConnection` delegate methods.
## Subclassing Notes
This is the base class of all network request operations. You may wish to create your own subclass in order to implement additional `NSURLConnection` delegate methods (see "`NSURLConnection` Delegate Methods" below), or to provide additional properties and/or class constructors.
If you are creating a subclass that communicates over the HTTP or HTTPS protocols, you may want to consider subclassing `AFHTTPRequestOperation` instead, as it supports specifying acceptable content types or status codes.
## NSURLConnection Delegate Methods
`AFURLConnectionOperation` implements the following `NSURLConnection` delegate methods:
- `connection:didReceiveResponse:`
- `connection:didReceiveData:`
- `connectionDidFinishLoading:`
- `connection:didFailWithError:`
- `connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:`
- `connection:willCacheResponse:`
- `connectionShouldUseCredentialStorage:`
- `connection:needNewBodyStream:`
- `connection:willSendRequestForAuthenticationChallenge:`
If any of these methods are overridden in a subclass, they _must_ call the `super` implementation first.
## Class Constructors
Class constructors, or methods that return an unowned instance, are the preferred way for subclasses to encapsulate any particular logic for handling the setup or parsing of response data. For instance, `AFJSONRequestOperation` provides `JSONRequestOperationWithRequest:success:failure:`, which takes block arguments, whose parameter on for a successful request is the JSON object initialized from the `response data`.
## Callbacks and Completion Blocks
The built-in `completionBlock` provided by `NSOperation` allows for custom behavior to be executed after the request finishes. It is a common pattern for class constructors in subclasses to take callback block parameters, and execute them conditionally in the body of its `completionBlock`. Make sure to handle cancelled operations appropriately when setting a `completionBlock` (i.e. returning early before parsing response data). See the implementation of any of the `AFHTTPRequestOperation` subclasses for an example of this.
Subclasses are strongly discouraged from overriding `setCompletionBlock:`, as `AFURLConnectionOperation`'s implementation includes a workaround to mitigate retain cycles, and what Apple rather ominously refers to as ["The Deallocation Problem"](http://developer.apple.com/library/ios/#technotes/tn2109/).
@discussion Error codes for AFNetworkingErrorDomain correspond to codes in NSURLErrorDomain. ## SSL Pinning
Relying on the CA trust model to validate SSL certificates exposes your app to security vulnerabilities, such as man-in-the-middle attacks. For applications that connect to known servers, SSL certificate pinning provides an increased level of security, by checking server certificate validity against those specified in the app bundle.
SSL with certificate pinning is strongly recommended for any application that transmits sensitive information to an external webservice.
When `defaultSSLPinningMode` is defined on `AFHTTPClient` and the Security framework is linked, connections will be validated on all matching certificates with a `.cer` extension in the bundle root.
## NSCoding & NSCopying Conformance
`AFURLConnectionOperation` conforms to the `NSCoding` and `NSCopying` protocols, allowing operations to be archived to disk, and copied in memory, respectively. However, because of the intrinsic limitations of capturing the exact state of an operation at a particular moment, there are some important caveats to keep in mind:
### NSCoding Caveats
- Encoded operations do not include any block or stream properties. Be sure to set `completionBlock`, `outputStream`, and any callback blocks as necessary when using `-initWithCoder:` or `NSKeyedUnarchiver`.
- Operations are paused on `encodeWithCoder:`. If the operation was encoded while paused or still executing, its archived state will return `YES` for `isReady`. Otherwise, the state of an operation when encoding will remain unchanged.
### NSCopying Caveats
- `-copy` and `-copyWithZone:` return a new operation with the `NSURLRequest` of the original. So rather than an exact copy of the operation at that particular instant, the copying mechanism returns a completely new instance, which can be useful for retrying operations.
- A copy of an operation will not include the `outputStream` of the original.
- Operation copies do not include `completionBlock`. `completionBlock` often strongly captures a reference to `self`, which would otherwise have the unintuitive side-effect of pointing to the _original_ operation when copied.
*/
typedef enum {
AFSSLPinningModeNone,
AFSSLPinningModePublicKey,
AFSSLPinningModeCertificate,
} AFURLConnectionOperationSSLPinningMode;
@interface AFURLConnectionOperation : NSOperation <NSURLConnectionDelegate,
#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000) || \
(defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080)
NSURLConnectionDataDelegate,
#endif
NSCoding, NSCopying>
///-------------------------------
/// @name Accessing Run Loop Modes
///-------------------------------
/**
The run loop modes in which the operation will run on the network thread. By default, this is a single-member set containing `NSRunLoopCommonModes`.
*/
@property (nonatomic, strong) NSSet *runLoopModes;
///-----------------------------------------
/// @name Getting URL Connection Information
///-----------------------------------------
/**
The request used by the operation's connection.
*/
@property (readonly, nonatomic, strong) NSURLRequest *request;
/**
The last response received by the operation's connection.
*/
@property (readonly, nonatomic, strong) NSURLResponse *response;
/**
The error, if any, that occurred in the lifecycle of the request.
*/
@property (readonly, nonatomic, strong) NSError *error;
/**
Whether the connection should accept an invalid SSL certificate.
If `_AFNETWORKING_ALLOW_INVALID_SSL_CERTIFICATES_` is set, this property defaults to `YES` for backwards compatibility. Otherwise, this property defaults to `NO`.
*/
@property (nonatomic, assign) BOOL allowsInvalidSSLCertificate;
///----------------------------
/// @name Getting Response Data
///----------------------------
/**
The data received during the request.
*/
@property (readonly, nonatomic, strong) NSData *responseData;
/**
The string representation of the response data.
*/
@property (readonly, nonatomic, copy) NSString *responseString;
/**
The string encoding of the response.
If the response does not specify a valid string encoding, `responseStringEncoding` will return `NSUTF8StringEncoding`.
*/
@property (readonly, nonatomic, assign) NSStringEncoding responseStringEncoding;
///-------------------------------
/// @name Managing URL Credentials
///-------------------------------
/**
Whether the URL connection should consult the credential storage for authenticating the connection. `YES` by default.
This is the value that is returned in the `NSURLConnectionDelegate` method `-connectionShouldUseCredentialStorage:`.
*/
@property (nonatomic, assign) BOOL shouldUseCredentialStorage;
/**
The credential used for authentication challenges in `-connection:didReceiveAuthenticationChallenge:`.
This will be overridden by any shared credentials that exist for the username or password of the request URL, if present.
*/
@property (nonatomic, strong) NSURLCredential *credential;
/**
The pinning mode which will be used for SSL connections. `AFSSLPinningModePublicKey` by default.
SSL Pinning requires that the Security framework is linked with the binary. See the "SSL Pinning" section in the `AFURLConnectionOperation`" header for more information.
*/
@property (nonatomic, assign) AFURLConnectionOperationSSLPinningMode SSLPinningMode;
///------------------------
/// @name Accessing Streams
///------------------------
/**
The input stream used to read data to be sent during the request.
This property acts as a proxy to the `HTTPBodyStream` property of `request`.
*/
@property (nonatomic, strong) NSInputStream *inputStream;
/**
The output stream that is used to write data received until the request is finished.
By default, data is accumulated into a buffer that is stored into `responseData` upon completion of the request. When `outputStream` is set, the data will not be accumulated into an internal buffer, and as a result, the `responseData` property of the completed request will be `nil`. The output stream will be scheduled in the network thread runloop upon being set.
*/
@property (nonatomic, strong) NSOutputStream *outputStream;
///---------------------------------------------
/// @name Managing Request Operation Information
///---------------------------------------------
/**
The user info dictionary for the receiver.
*/
@property (nonatomic, strong) NSDictionary *userInfo;
///------------------------------------------------------
/// @name Initializing an AFURLConnectionOperation Object
///------------------------------------------------------
/**
Initializes and returns a newly allocated operation object with a url connection configured with the specified url request.
This is the designated initializer.
@param urlRequest The request object to be used by the operation connection.
*/
- (id)initWithRequest:(NSURLRequest *)urlRequest;
///----------------------------------
/// @name Pausing / Resuming Requests
///----------------------------------
/**
Pauses the execution of the request operation.
A paused operation returns `NO` for `-isReady`, `-isExecuting`, and `-isFinished`. As such, it will remain in an `NSOperationQueue` until it is either cancelled or resumed. Pausing a finished, cancelled, or paused operation has no effect.
*/
- (void)pause;
/**
Whether the request operation is currently paused.
@return `YES` if the operation is currently paused, otherwise `NO`.
*/
- (BOOL)isPaused;
/**
Resumes the execution of the paused request operation.
Pause/Resume behavior varies depending on the underlying implementation for the operation class. In its base implementation, resuming a paused requests restarts the original request. However, since HTTP defines a specification for how to request a specific content range, `AFHTTPRequestOperation` will resume downloading the request from where it left off, instead of restarting the original request.
*/
- (void)resume;
///----------------------------------------------
/// @name Configuring Backgrounding Task Behavior
///----------------------------------------------
/**
Specifies that the operation should continue execution after the app has entered the background, and the expiration handler for that background task.
@param handler A handler to be called shortly before the applications remaining background time reaches 0. The handler is wrapped in a block that cancels the operation, and cleans up and marks the end of execution, unlike the `handler` parameter in `UIApplication -beginBackgroundTaskWithExpirationHandler:`, which expects this to be done in the handler itself. The handler is called synchronously on the main thread, thus blocking the applications suspension momentarily while the application is notified.
*/
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
- (void)setShouldExecuteAsBackgroundTaskWithExpirationHandler:(void (^)(void))handler;
#endif
///---------------------------------
/// @name Setting Progress Callbacks
///---------------------------------
/**
Sets a callback to be called when an undetermined number of bytes have been uploaded to the server.
@param block A block object to be called when an undetermined number of bytes have been uploaded to the server. This block has no return value and takes three arguments: the number of bytes written since the last time the upload progress block was called, the total bytes written, and the total bytes expected to be written during the request, as initially determined by the length of the HTTP body. This block may be called multiple times, and will execute on the main thread.
*/
- (void)setUploadProgressBlock:(void (^)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))block;
/**
Sets a callback to be called when an undetermined number of bytes have been downloaded from the server.
@param block A block object to be called when an undetermined number of bytes have been downloaded from the server. This block has no return value and takes three arguments: the number of bytes read since the last time the download progress block was called, the total bytes read, and the total bytes expected to be read during the request, as initially determined by the expected content size of the `NSHTTPURLResponse` object. This block may be called multiple times, and will execute on the main thread.
*/
- (void)setDownloadProgressBlock:(void (^)(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead))block;
///-------------------------------------------------
/// @name Setting NSURLConnection Delegate Callbacks
///-------------------------------------------------
/**
Sets a block to be executed when the connection will authenticate a challenge in order to download its request, as handled by the `NSURLConnectionDelegate` method `connection:willSendRequestForAuthenticationChallenge:`.
@param block A block object to be executed when the connection will authenticate a challenge in order to download its request. The block has no return type and takes two arguments: the URL connection object, and the challenge that must be authenticated. This block must invoke one of the challenge-responder methods (NSURLAuthenticationChallengeSender protocol).
If `allowsInvalidSSLCertificate` is set to YES, `connection:willSendRequestForAuthenticationChallenge:` will attempt to have the challenge sender use credentials with invalid SSL certificates.
*/
- (void)setWillSendRequestForAuthenticationChallengeBlock:(void (^)(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge))block;
/**
Sets a block to be executed when the server redirects the request from one URL to another URL, or when the request URL changed by the `NSURLProtocol` subclass handling the request in order to standardize its format, as handled by the `NSURLConnectionDelegate` method `connection:willSendRequest:redirectResponse:`.
@param block A block object to be executed when the request URL was changed. The block returns an `NSURLRequest` object, the URL request to redirect, and takes three arguments: the URL connection object, the the proposed redirected request, and the URL response that caused the redirect.
*/
- (void)setRedirectResponseBlock:(NSURLRequest * (^)(NSURLConnection *connection, NSURLRequest *request, NSURLResponse *redirectResponse))block;
/**
Sets a block to be executed to modify the response a connection will cache, if any, as handled by the `NSURLConnectionDelegate` method `connection:willCacheResponse:`.
@param block A block object to be executed to determine what response a connection will cache, if any. The block returns an `NSCachedURLResponse` object, the cached response to store in memory or `nil` to prevent the response from being cached, and takes two arguments: the URL connection object, and the cached response provided for the request.
*/
- (void)setCacheResponseBlock:(NSCachedURLResponse * (^)(NSURLConnection *connection, NSCachedURLResponse *cachedResponse))block;
@end
///----------------
/// @name Constants
///----------------
/**
## SSL Pinning Options
The following constants are provided by `AFURLConnectionOperation` as possible SSL Pinning options.
enum {
AFSSLPinningModeNone,
AFSSLPinningModePublicKey,
AFSSLPinningModeCertificate,
}
`AFSSLPinningModeNone`
Do not pin SSL connections
`AFSSLPinningModePublicKey`
Pin SSL connections to certificate public key (SPKI).
`AFSSLPinningModeCertificate`
Pin SSL connections to exact certificate. This may cause problems when your certificate expires and needs re-issuance.
## User info dictionary keys
These keys may exist in the user info dictionary, in addition to those defined for NSError.
- `NSString * const AFNetworkingOperationFailingURLRequestErrorKey`
- `NSString * const AFNetworkingOperationFailingURLResponseErrorKey`
### Constants
`AFNetworkingOperationFailingURLRequestErrorKey`
The corresponding value is an `NSURLRequest` containing the request of the operation associated with an error. This key is only present in the `AFNetworkingErrorDomain`.
`AFNetworkingOperationFailingURLResponseErrorKey`
The corresponding value is an `NSURLResponse` containing the response of the operation associated with an error. This key is only present in the `AFNetworkingErrorDomain`.
## Error Domains
The following error domain is predefined.
- `NSString * const AFNetworkingErrorDomain`
### Constants
`AFNetworkingErrorDomain`
AFNetworking errors. Error codes for `AFNetworkingErrorDomain` correspond to codes in `NSURLErrorDomain`.
*/ */
extern NSString * const AFNetworkingErrorDomain; extern NSString * const AFNetworkingErrorDomain;
extern NSString * const AFNetworkingOperationFailingURLRequestErrorKey;
extern NSString * const AFNetworkingOperationFailingURLResponseErrorKey;
///--------------------
/// @name Notifications
///--------------------
/** /**
Posted when an operation begins executing. Posted when an operation begins executing.
@ -38,215 +370,3 @@ extern NSString * const AFNetworkingOperationDidStartNotification;
Posted when an operation finishes. Posted when an operation finishes.
*/ */
extern NSString * const AFNetworkingOperationDidFinishNotification; extern NSString * const AFNetworkingOperationDidFinishNotification;
/**
`AFURLConnectionOperation` is an `NSOperation` that implements NSURLConnection delegate methods.
## Subclassing Notes
This is the base class of all network request operations. You may wish to create your own subclass in order to implement additional `NSURLConnection` delegate methods (see "`NSURLConnection` Delegate Methods" below), or to provide additional properties and/or class constructors.
If you are creating a subclass that communicates over the HTTP or HTTPS protocols, you may want to consider subclassing `AFHTTPRequestOperation` instead, as it supports specifying acceptable content types or status codes.
## NSURLConnection Delegate Methods
`AFURLConnectionOperation` implements the following `NSURLConnection` delegate methods:
- `connection:didReceiveResponse:`
- `connection:didReceiveData:`
- `connectionDidFinishLoading:`
- `connection:didFailWithError:`
- `connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:`
- `connection:willCacheResponse:`
- `connection:canAuthenticateAgainstProtectionSpace:`
- `connection:didReceiveAuthenticationChallenge:`
If any of these methods are overriden in a subclass, they _must_ call the `super` implementation first.
## Class Constructors
Class constructors, or methods that return an unowned (zero retain count) instance, are the preferred way for subclasses to encapsulate any particular logic for handling the setup or parsing of response data. For instance, `AFJSONRequestOperation` provides `JSONRequestOperationWithRequest:success:failure:`, which takes block arguments, whose parameter on for a successful request is the JSON object initialized from the `response data`.
## Callbacks and Completion Blocks
The built-in `completionBlock` provided by `NSOperation` allows for custom behavior to be executed after the request finishes. It is a common pattern for class constructors in subclasses to take callback block parameters, and execute them conditionally in the body of its `completionBlock`. Make sure to handle cancelled operations appropriately when setting a `completionBlock` (e.g. returning early before parsing response data). See the implementation of any of the `AFHTTPRequestOperation` subclasses for an example of this.
@warning Subclasses are strongly discouraged from overriding `setCompletionBlock:`, as `AFURLConnectionOperation`'s implementation includes a workaround to mitigate retain cycles, and what Apple rather ominously refers to as "The Deallocation Problem" (See http://developer.apple.com/library/ios/technotes/tn2109/_index.html#//apple_ref/doc/uid/DTS40010274-CH1-SUBSECTION11)
@warning Attempting to load a `file://` URL in iOS 4 may result in an `NSInvalidArgumentException`, caused by the connection returning `NSURLResponse` rather than `NSHTTPURLResponse`, which is the behavior as of iOS 5.
*/
@interface AFURLConnectionOperation : NSOperation
///-------------------------------
/// @name Accessing Run Loop Modes
///-------------------------------
/**
The run loop modes in which the operation will run on the network thread. By default, this is a single-member set containing `NSRunLoopCommonModes`.
*/
@property (nonatomic, retain) NSSet *runLoopModes;
///-----------------------------------------
/// @name Getting URL Connection Information
///-----------------------------------------
/**
The request used by the operation's connection.
*/
@property (readonly, nonatomic, retain) NSURLRequest *request;
/**
The last response received by the operation's connection.
*/
@property (readonly, nonatomic, retain) NSURLResponse *response;
/**
The error, if any, that occured in the lifecycle of the request.
*/
@property (readonly, nonatomic, retain) NSError *error;
///----------------------------
/// @name Getting Response Data
///----------------------------
/**
The data received during the request.
*/
@property (readonly, nonatomic, retain) NSData *responseData;
/**
The string representation of the response data.
@discussion This method uses the string encoding of the response, or if UTF-8 if not specified, to construct a string from the response data.
*/
@property (readonly, nonatomic, copy) NSString *responseString;
///------------------------
/// @name Accessing Streams
///------------------------
/**
The input stream used to read data to be sent during the request.
@discussion This property acts as a proxy to the `HTTPBodyStream` property of `request`.
*/
@property (nonatomic, retain) NSInputStream *inputStream;
/**
The output stream that is used to write data received until the request is finished.
@discussion By default, data is accumulated into a buffer that is stored into `responseData` upon completion of the request. When `outputStream` is set, the data will not be accumulated into an internal buffer, and as a result, the `responseData` property of the completed request will be `nil`. The output stream will be scheduled in the network thread runloop upon being set.
*/
@property (nonatomic, retain) NSOutputStream *outputStream;
///------------------------------------------------------
/// @name Initializing an AFURLConnectionOperation Object
///------------------------------------------------------
/**
Initializes and returns a newly allocated operation object with a url connection configured with the specified url request.
@param urlRequest The request object to be used by the operation connection.
@discussion This is the designated initializer.
*/
- (id)initWithRequest:(NSURLRequest *)urlRequest;
///----------------------------------
/// @name Pausing / Resuming Requests
///----------------------------------
/**
Pauses the execution of the request operation.
@discussion A paused operation returns `NO` for `-isReady`, `-isExecuting`, and `-isFinished`. As such, it will remain in an `NSOperationQueue` until it is either cancelled or resumed. Pausing a finished or cancelled operation has no effect.
*/
- (void)pause;
/**
Whether the request operation is currently paused.
@return `YES` if the operation is currently paused, otherwise `NO`.
*/
- (BOOL)isPaused;
/**
Resumes the execution of the paused request operation.
@discussion Pause/Resume behavior varies depending on the underlying implementation for the operation class. In its base implementation, resuming a paused requests restarts the original request. However, since HTTP defines a specification for how to request a specific content range, `AFHTTPRequestOperation` will resume downloading the request from where it left off, instead of restarting the original request.
*/
- (void)resume;
///----------------------------------------------
/// @name Configuring Backgrounding Task Behavior
///----------------------------------------------
/**
Specifies that the operation should continue execution after the app has entered the background, and the expiration handler for that background task.
@param handler A handler to be called shortly before the applications remaining background time reaches 0. The handler is wrapped in a block that cancels the operation, and cleans up and marks the end of execution, unlike the `handler` parameter in `UIApplication -beginBackgroundTaskWithExpirationHandler:`, which expects this to be done in the handler itself. The handler is called synchronously on the main thread, thus blocking the applications suspension momentarily while the application is notified.
*/
#if __IPHONE_OS_VERSION_MIN_REQUIRED
- (void)setShouldExecuteAsBackgroundTaskWithExpirationHandler:(void (^)(void))handler;
#endif
///---------------------------------
/// @name Setting Progress Callbacks
///---------------------------------
/**
Sets a callback to be called when an undetermined number of bytes have been uploaded to the server.
@param block A block object to be called when an undetermined number of bytes have been uploaded to the server. This block has no return value and takes three arguments: the number of bytes written since the last time the upload progress block was called, the total bytes written, and the total bytes expected to be written during the request, as initially determined by the length of the HTTP body. This block may be called multiple times.
@see setDownloadProgressBlock
*/
- (void)setUploadProgressBlock:(void (^)(NSInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))block;
/**
Sets a callback to be called when an undetermined number of bytes have been downloaded from the server.
@param block A block object to be called when an undetermined number of bytes have been downloaded from the server. This block has no return value and takes three arguments: the number of bytes read since the last time the download progress block was called, the total bytes read, and the total bytes expected to be read during the request, as initially determined by the expected content size of the `NSHTTPURLResponse` object. This block may be called multiple times.
@see setUploadProgressBlock
*/
- (void)setDownloadProgressBlock:(void (^)(NSInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead))block;
///-------------------------------------------------
/// @name Setting NSURLConnection Delegate Callbacks
///-------------------------------------------------
/**
Sets a block to be executed to determine whether the connection should be able to respond to a protection space's form of authentication, as handled by the `NSURLConnectionDelegate` method `connection:canAuthenticateAgainstProtectionSpace:`.
@param block A block object to be executed to determine whether the connection should be able to respond to a protection space's form of authentication. The block has a `BOOL` return type and takes two arguments: the URL connection object, and the protection space to authenticate against.
@discussion If `_AFNETWORKING_ALLOW_INVALID_SSL_CERTIFICATES_` is defined, `connection:canAuthenticateAgainstProtectionSpace:` will accept invalid SSL certificates, returning `YES` if the protection space authentication method is `NSURLAuthenticationMethodServerTrust`.
*/
- (void)setAuthenticationAgainstProtectionSpaceBlock:(BOOL (^)(NSURLConnection *connection, NSURLProtectionSpace *protectionSpace))block;
/**
Sets a block to be executed when the connection must authenticate a challenge in order to download its request, as handled by the `NSURLConnectionDelegate` method `connection:didReceiveAuthenticationChallenge:`.
@param block A block object to be executed when the connection must authenticate a challenge in order to download its request. The block has no return type and takes two arguments: the URL connection object, and the challenge that must be authenticated.
@discussion If `_AFNETWORKING_ALLOW_INVALID_SSL_CERTIFICATES_` is defined, `connection:didReceiveAuthenticationChallenge:` will attempt to have the challenge sender use credentials with invalid SSL certificates.
*/
- (void)setAuthenticationChallengeBlock:(void (^)(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge))block;
/**
Sets a block to be executed when the server redirects the request from one URL to another URL, or when the request URL changed by the `NSURLProtocol` subclass handling the request in order to standardize its format, as handled by the `NSURLConnectionDelegate` method `connection:willSendRequest:redirectResponse:`.
@param block A block object to be executed when the request URL was changed. The block returns an `NSURLRequest` object, the URL request to redirect, and takes three arguments: the URL connection object, the the proposed redirected request, and the URL response that caused the redirect.
*/
- (void)setRedirectResponseBlock:(NSURLRequest * (^)(NSURLConnection *connection, NSURLRequest *request, NSURLResponse *redirectResponse))block;
/**
Sets a block to be executed to modify the response a connection will cache, if any, as handled by the `NSURLConnectionDelegate` method `connection:willCacheResponse:`.
@param block A block object to be executed to determine what response a connection will cache, if any. The block returns an `NSCachedURLResponse` object, the cached response to store in memory or `nil` to prevent the response from being cached, and takes two arguments: the URL connection object, and the cached response provided for the request.
*/
- (void)setCacheResponseBlock:(NSCachedURLResponse * (^)(NSURLConnection *connection, NSCachedURLResponse *cachedResponse))block;
@end

677
clients/ios/AFNetworking/AFURLConnectionOperation.m Normal file → Executable file

File diff suppressed because it is too large Load diff

46
clients/ios/AFNetworking/AFXMLRequestOperation.h Normal file → Executable file
View file

@ -1,17 +1,17 @@
// AFXMLRequestOperation.h // AFXMLRequestOperation.h
// //
// Copyright (c) 2011 Gowalla (http://gowalla.com/) // Copyright (c) 2011 Gowalla (http://gowalla.com/)
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights // in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is // copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions: // furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -27,16 +27,16 @@
/** /**
`AFXMLRequestOperation` is a subclass of `AFHTTPRequestOperation` for downloading and working with XML response data. `AFXMLRequestOperation` is a subclass of `AFHTTPRequestOperation` for downloading and working with XML response data.
## Acceptable Content Types ## Acceptable Content Types
By default, `AFXMLRequestOperation` accepts the following MIME types, which includes the official standard, `application/xml`, as well as other commonly-used types: By default, `AFXMLRequestOperation` accepts the following MIME types, which includes the official standard, `application/xml`, as well as other commonly-used types:
- `application/xml` - `application/xml`
- `text/xml` - `text/xml`
## Use With AFHTTPClient ## Use With AFHTTPClient
When `AFXMLRequestOperation` is registered with `AFHTTPClient`, the response object in the success callback of `HTTPRequestOperationWithRequest:success:failure:` will be an instance of `NSXMLParser`. On platforms that support `NSXMLDocument`, you have the option to ignore the response object, and simply use the `responseXMLDocument` property of the operation argument of the callback. When `AFXMLRequestOperation` is registered with `AFHTTPClient`, the response object in the success callback of `HTTPRequestOperationWithRequest:success:failure:` will be an instance of `NSXMLParser`. On platforms that support `NSXMLDocument`, you have the option to ignore the response object, and simply use the `responseXMLDocument` property of the operation argument of the callback.
*/ */
@interface AFXMLRequestOperation : AFHTTPRequestOperation @interface AFXMLRequestOperation : AFHTTPRequestOperation
@ -48,42 +48,42 @@
/** /**
An `NSXMLParser` object constructed from the response data. An `NSXMLParser` object constructed from the response data.
*/ */
@property (readonly, nonatomic, retain) NSXMLParser *responseXMLParser; @property (readonly, nonatomic, strong) NSXMLParser *responseXMLParser;
#if __MAC_OS_X_VERSION_MIN_REQUIRED #ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
/** /**
An `NSXMLDocument` object constructed from the response data. If an error occurs while parsing, `nil` will be returned, and the `error` property will be set to the error. An `NSXMLDocument` object constructed from the response data. If an error occurs while parsing, `nil` will be returned, and the `error` property will be set to the error.
*/ */
@property (readonly, nonatomic, retain) NSXMLDocument *responseXMLDocument; @property (readonly, nonatomic, strong) NSXMLDocument *responseXMLDocument;
#endif #endif
/** /**
Creates and returns an `AFXMLRequestOperation` object and sets the specified success and failure callbacks. Creates and returns an `AFXMLRequestOperation` object and sets the specified success and failure callbacks.
@param urlRequest The request object to be loaded asynchronously during execution of the operation @param urlRequest The request object to be loaded asynchronously during execution of the operation
@param success A block object to be executed when the operation finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the XML parser constructed with the response data of request. @param success A block object to be executed when the operation finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the XML parser constructed with the response data of request.
@param failure A block object to be executed when the operation finishes unsuccessfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error describing the network error that occurred. @param failure A block object to be executed when the operation finishes unsuccessfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error describing the network error that occurred.
@return A new XML request operation @return A new XML request operation
*/ */
+ (AFXMLRequestOperation *)XMLParserRequestOperationWithRequest:(NSURLRequest *)urlRequest + (instancetype)XMLParserRequestOperationWithRequest:(NSURLRequest *)urlRequest
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser))success success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser))success
failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLParser *XMLParse))failure; failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLParser *XMLParser))failure;
#if __MAC_OS_X_VERSION_MIN_REQUIRED #ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
/** /**
Creates and returns an `AFXMLRequestOperation` object and sets the specified success and failure callbacks. Creates and returns an `AFXMLRequestOperation` object and sets the specified success and failure callbacks.
@param urlRequest The request object to be loaded asynchronously during execution of the operation @param urlRequest The request object to be loaded asynchronously during execution of the operation
@param success A block object to be executed when the operation finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the XML document created from the response data of request. @param success A block object to be executed when the operation finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the XML document created from the response data of request.
@param failure A block object to be executed when the operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data as XML. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error describing the network or parsing error that occurred. @param failure A block object to be executed when the operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data as XML. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error describing the network or parsing error that occurred.
@return A new XML request operation @return A new XML request operation
*/ */
+ (AFXMLRequestOperation *)XMLDocumentRequestOperationWithRequest:(NSURLRequest *)urlRequest + (instancetype)XMLDocumentRequestOperationWithRequest:(NSURLRequest *)urlRequest
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLDocument *document))success success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLDocument *document))success
failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLDocument *document))failure; failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLDocument *document))failure;
#endif #endif
@end @end

92
clients/ios/AFNetworking/AFXMLRequestOperation.m Normal file → Executable file
View file

@ -1,17 +1,17 @@
// AFXMLRequestOperation.m // AFXMLRequestOperation.m
// //
// Copyright (c) 2011 Gowalla (http://gowalla.com/) // Copyright (c) 2011 Gowalla (http://gowalla.com/)
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights // in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is // copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions: // furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -24,35 +24,36 @@
#include <Availability.h> #include <Availability.h>
static dispatch_queue_t af_xml_request_operation_processing_queue;
static dispatch_queue_t xml_request_operation_processing_queue() { static dispatch_queue_t xml_request_operation_processing_queue() {
if (af_xml_request_operation_processing_queue == NULL) { static dispatch_queue_t af_xml_request_operation_processing_queue;
af_xml_request_operation_processing_queue = dispatch_queue_create("com.alamofire.networking.xml-request.processing", 0); static dispatch_once_t onceToken;
} dispatch_once(&onceToken, ^{
af_xml_request_operation_processing_queue = dispatch_queue_create("com.alamofire.networking.xml-request.processing", DISPATCH_QUEUE_CONCURRENT);
});
return af_xml_request_operation_processing_queue; return af_xml_request_operation_processing_queue;
} }
@interface AFXMLRequestOperation () @interface AFXMLRequestOperation ()
@property (readwrite, nonatomic, retain) NSXMLParser *responseXMLParser; @property (readwrite, nonatomic, strong) NSXMLParser *responseXMLParser;
#if __MAC_OS_X_VERSION_MIN_REQUIRED #ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
@property (readwrite, nonatomic, retain) NSXMLDocument *responseXMLDocument; @property (readwrite, nonatomic, strong) NSXMLDocument *responseXMLDocument;
#endif #endif
@property (readwrite, nonatomic, retain) NSError *XMLError; @property (readwrite, nonatomic, strong) NSError *XMLError;
@end @end
@implementation AFXMLRequestOperation @implementation AFXMLRequestOperation
@synthesize responseXMLParser = _responseXMLParser; @synthesize responseXMLParser = _responseXMLParser;
#if __MAC_OS_X_VERSION_MIN_REQUIRED #ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
@synthesize responseXMLDocument = _responseXMLDocument; @synthesize responseXMLDocument = _responseXMLDocument;
#endif #endif
@synthesize XMLError = _XMLError; @synthesize XMLError = _XMLError;
+ (AFXMLRequestOperation *)XMLParserRequestOperationWithRequest:(NSURLRequest *)urlRequest + (instancetype)XMLParserRequestOperationWithRequest:(NSURLRequest *)urlRequest
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser))success success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser))success
failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLParser *XMLParser))failure failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLParser *XMLParser))failure
{ {
AFXMLRequestOperation *requestOperation = [[[self alloc] initWithRequest:urlRequest] autorelease]; AFXMLRequestOperation *requestOperation = [(AFXMLRequestOperation *)[self alloc] initWithRequest:urlRequest];
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if (success) { if (success) {
success(operation.request, operation.response, responseObject); success(operation.request, operation.response, responseObject);
@ -62,19 +63,19 @@ static dispatch_queue_t xml_request_operation_processing_queue() {
failure(operation.request, operation.response, error, [(AFXMLRequestOperation *)operation responseXMLParser]); failure(operation.request, operation.response, error, [(AFXMLRequestOperation *)operation responseXMLParser]);
} }
}]; }];
return requestOperation; return requestOperation;
} }
#if __MAC_OS_X_VERSION_MIN_REQUIRED #ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
+ (AFXMLRequestOperation *)XMLDocumentRequestOperationWithRequest:(NSURLRequest *)urlRequest + (instancetype)XMLDocumentRequestOperationWithRequest:(NSURLRequest *)urlRequest
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLDocument *document))success success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLDocument *document))success
failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLDocument *document))failure failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLDocument *document))failure
{ {
AFXMLRequestOperation *requestOperation = [[[self alloc] initWithRequest:urlRequest] autorelease]; AFXMLRequestOperation *requestOperation = [[self alloc] initWithRequest:urlRequest];
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, __unused id responseObject) { [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, __unused id responseObject) {
if (success) { if (success) {
NSXMLDocument *XMLDocument = [(AFXMLRequestOperation *)operation responseXMLDocument]; NSXMLDocument *XMLDocument = [(AFXMLRequestOperation *)operation responseXMLDocument];
success(operation.request, operation.response, XMLDocument); success(operation.request, operation.response, XMLDocument);
} }
} failure:^(AFHTTPRequestOperation *operation, NSError *error) { } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
@ -83,39 +84,28 @@ static dispatch_queue_t xml_request_operation_processing_queue() {
failure(operation.request, operation.response, error, XMLDocument); failure(operation.request, operation.response, error, XMLDocument);
} }
}]; }];
return requestOperation; return requestOperation;
} }
#endif #endif
- (void)dealloc {
[_responseXMLParser release];
#if __MAC_OS_X_VERSION_MIN_REQUIRED
[_responseXMLDocument release];
#endif
[_XMLError release];
[super dealloc];
}
- (NSXMLParser *)responseXMLParser { - (NSXMLParser *)responseXMLParser {
if (!_responseXMLParser && [self.responseData length] > 0 && [self isFinished]) { if (!_responseXMLParser && [self.responseData length] > 0 && [self isFinished]) {
self.responseXMLParser = [[[NSXMLParser alloc] initWithData:self.responseData] autorelease]; self.responseXMLParser = [[NSXMLParser alloc] initWithData:self.responseData];
} }
return _responseXMLParser; return _responseXMLParser;
} }
#if __MAC_OS_X_VERSION_MIN_REQUIRED #ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
- (NSXMLDocument *)responseXMLDocument { - (NSXMLDocument *)responseXMLDocument {
if (!_responseXMLDocument && [self.responseData length] > 0 && [self isFinished]) { if (!_responseXMLDocument && [self.responseData length] > 0 && [self isFinished]) {
NSError *error = nil; NSError *error = nil;
self.responseXMLDocument = [[[NSXMLDocument alloc] initWithData:self.responseData options:0 error:&error] autorelease]; self.responseXMLDocument = [[NSXMLDocument alloc] initWithData:self.responseData options:0 error:&error];
self.XMLError = error; self.XMLError = error;
} }
return _responseXMLDocument; return _responseXMLDocument;
} }
#endif #endif
@ -132,7 +122,7 @@ static dispatch_queue_t xml_request_operation_processing_queue() {
- (void)cancel { - (void)cancel {
[super cancel]; [super cancel];
self.responseXMLParser.delegate = nil; self.responseXMLParser.delegate = nil;
} }
@ -149,29 +139,29 @@ static dispatch_queue_t xml_request_operation_processing_queue() {
- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success - (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{ {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
#pragma clang diagnostic ignored "-Wgnu"
self.completionBlock = ^ { self.completionBlock = ^ {
if ([self isCancelled]) {
return;
}
dispatch_async(xml_request_operation_processing_queue(), ^(void) { dispatch_async(xml_request_operation_processing_queue(), ^(void) {
NSXMLParser *XMLParser = self.responseXMLParser; NSXMLParser *XMLParser = self.responseXMLParser;
if (self.error) { if (self.error) {
if (failure) { if (failure) {
dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ dispatch_async(self.failureCallbackQueue ?: dispatch_get_main_queue(), ^{
failure(self, self.error); failure(self, self.error);
}); });
} }
} else { } else {
if (success) { if (success) {
dispatch_async(self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ dispatch_async(self.successCallbackQueue ?: dispatch_get_main_queue(), ^{
success(self, XMLParser); success(self, XMLParser);
}); });
} }
} }
}); });
}; };
#pragma clang diagnostic pop
} }
@end @end

28
clients/ios/AFNetworking/UIImageView+AFNetworking.h Normal file → Executable file
View file

@ -1,17 +1,17 @@
// UIImageView+AFNetworking.h // UIImageView+AFNetworking.h
// //
// Copyright (c) 2011 Gowalla (http://gowalla.com/) // Copyright (c) 2011 Gowalla (http://gowalla.com/)
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights // in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is // copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions: // furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -35,34 +35,36 @@
/** /**
Creates and enqueues an image request operation, which asynchronously downloads the image from the specified URL, and sets it the request is finished. Any previous image request for the receiver will be cancelled. If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished. Creates and enqueues an image request operation, which asynchronously downloads the image from the specified URL, and sets it the request is finished. Any previous image request for the receiver will be cancelled. If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished.
@discussion By default, URL requests have a cache policy of `NSURLCacheStorageAllowed` and a timeout interval of 30 seconds, and are set to use HTTP pipelining, and not handle cookies. To configure URL requests differently, use `setImageWithURLRequest:placeholderImage:success:failure:` By default, URL requests have a cache policy of `NSURLCacheStorageAllowed` and a timeout interval of 30 seconds, and are set not handle cookies. To configure URL requests differently, use `setImageWithURLRequest:placeholderImage:success:failure:`
@param url The URL used for the image request. @param url The URL used for the image request.
*/ */
- (void)setImageWithURL:(NSURL *)url; - (void)setImageWithURL:(NSURL *)url;
/** /**
Creates and enqueues an image request operation, which asynchronously downloads the image from the specified URL. Any previous image request for the receiver will be cancelled. If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished. Creates and enqueues an image request operation, which asynchronously downloads the image from the specified URL. Any previous image request for the receiver will be cancelled. If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished.
By default, URL requests have a cache policy of `NSURLCacheStorageAllowed` and a timeout interval of 30 seconds, and are set not handle cookies. To configure URL requests differently, use `setImageWithURLRequest:placeholderImage:success:failure:`
@param url The URL used for the image request. @param url The URL used for the image request.
@param placeholderImage The image to be set initially, until the image request finishes. If `nil`, the image view will not change its image until the image request finishes. @param placeholderImage The image to be set initially, until the image request finishes. If `nil`, the image view will not change its image until the image request finishes.
*/
@discussion By default, URL requests have a cache policy of `NSURLCacheStorageAllowed` and a timeout interval of 30 seconds, and are set to use HTTP pipelining, and not handle cookies. To configure URL requests differently, use `setImageWithURLRequest:placeholderImage:success:failure:` - (void)setImageWithURL:(NSURL *)url
*/
- (void)setImageWithURL:(NSURL *)url
placeholderImage:(UIImage *)placeholderImage; placeholderImage:(UIImage *)placeholderImage;
/** /**
Creates and enqueues an image request operation, which asynchronously downloads the image with the specified URL request object. Any previous image request for the receiver will be cancelled. If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished. Creates and enqueues an image request operation, which asynchronously downloads the image with the specified URL request object. Any previous image request for the receiver will be cancelled. If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished.
If a success block is specified, it is the responsibility of the block to set the image of the image view before returning. If no success block is specified, the default behavior of setting the image with `self.image = image` is executed.
@param urlRequest The URL request used for the image request. @param urlRequest The URL request used for the image request.
@param placeholderImage The image to be set initially, until the image request finishes. If `nil`, the image view will not change its image until the image request finishes. @param placeholderImage The image to be set initially, until the image request finishes. If `nil`, the image view will not change its image until the image request finishes.
@param success A block to be executed when the image request operation finishes successfully, with a status code in the 2xx range, and with an acceptable content type (e.g. `image/png`). This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the image created from the response data of request. If the image was returned from cache, the request and response parameters will be `nil`. @param success A block to be executed when the image request operation finishes successfully, with a status code in the 2xx range, and with an acceptable content type (e.g. `image/png`). This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the image created from the response data of request. If the image was returned from cache, the request and response parameters will be `nil`.
@param failure A block object to be executed when the image request operation finishes unsuccessfully, or that finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error object describing the network or parsing error that occurred. @param failure A block object to be executed when the image request operation finishes unsuccessfully, or that finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error object describing the network or parsing error that occurred.
*/ */
- (void)setImageWithURLRequest:(NSURLRequest *)urlRequest - (void)setImageWithURLRequest:(NSURLRequest *)urlRequest
placeholderImage:(UIImage *)placeholderImage placeholderImage:(UIImage *)placeholderImage
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success
failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure; failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure;

92
clients/ios/AFNetworking/UIImageView+AFNetworking.m Normal file → Executable file
View file

@ -1,17 +1,17 @@
// UIImageView+AFNetworking.m // UIImageView+AFNetworking.m
// //
// Copyright (c) 2011 Gowalla (http://gowalla.com/) // Copyright (c) 2011 Gowalla (http://gowalla.com/)
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights // in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is // copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions: // furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -23,7 +23,7 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import <objc/runtime.h> #import <objc/runtime.h>
#if __IPHONE_OS_VERSION_MIN_REQUIRED #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#import "UIImageView+AFNetworking.h" #import "UIImageView+AFNetworking.h"
@interface AFImageCache : NSCache @interface AFImageCache : NSCache
@ -37,7 +37,7 @@
static char kAFImageRequestOperationObjectKey; static char kAFImageRequestOperationObjectKey;
@interface UIImageView (_AFNetworking) @interface UIImageView (_AFNetworking)
@property (readwrite, nonatomic, retain, setter = af_setImageRequestOperation:) AFImageRequestOperation *af_imageRequestOperation; @property (readwrite, nonatomic, strong, setter = af_setImageRequestOperation:) AFImageRequestOperation *af_imageRequestOperation;
@end @end
@implementation UIImageView (_AFNetworking) @implementation UIImageView (_AFNetworking)
@ -58,12 +58,12 @@ static char kAFImageRequestOperationObjectKey;
+ (NSOperationQueue *)af_sharedImageRequestOperationQueue { + (NSOperationQueue *)af_sharedImageRequestOperationQueue {
static NSOperationQueue *_af_imageRequestOperationQueue = nil; static NSOperationQueue *_af_imageRequestOperationQueue = nil;
static dispatch_once_t onceToken;
if (!_af_imageRequestOperationQueue) { dispatch_once(&onceToken, ^{
_af_imageRequestOperationQueue = [[NSOperationQueue alloc] init]; _af_imageRequestOperationQueue = [[NSOperationQueue alloc] init];
[_af_imageRequestOperationQueue setMaxConcurrentOperationCount:8]; [_af_imageRequestOperationQueue setMaxConcurrentOperationCount:NSOperationQueueDefaultMaxConcurrentOperationCount];
} });
return _af_imageRequestOperationQueue; return _af_imageRequestOperationQueue;
} }
@ -73,7 +73,7 @@ static char kAFImageRequestOperationObjectKey;
dispatch_once(&oncePredicate, ^{ dispatch_once(&oncePredicate, ^{
_af_imageCache = [[AFImageCache alloc] init]; _af_imageCache = [[AFImageCache alloc] init];
}); });
return _af_imageCache; return _af_imageCache;
} }
@ -83,61 +83,65 @@ static char kAFImageRequestOperationObjectKey;
[self setImageWithURL:url placeholderImage:nil]; [self setImageWithURL:url placeholderImage:nil];
} }
- (void)setImageWithURL:(NSURL *)url - (void)setImageWithURL:(NSURL *)url
placeholderImage:(UIImage *)placeholderImage placeholderImage:(UIImage *)placeholderImage
{ {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30.0]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPShouldHandleCookies:NO]; [request addValue:@"image/*" forHTTPHeaderField:@"Accept"];
[request setHTTPShouldUsePipelining:YES];
[self setImageWithURLRequest:request placeholderImage:placeholderImage success:nil failure:nil]; [self setImageWithURLRequest:request placeholderImage:placeholderImage success:nil failure:nil];
} }
- (void)setImageWithURLRequest:(NSURLRequest *)urlRequest - (void)setImageWithURLRequest:(NSURLRequest *)urlRequest
placeholderImage:(UIImage *)placeholderImage placeholderImage:(UIImage *)placeholderImage
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success
failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure
{ {
[self cancelImageRequestOperation]; [self cancelImageRequestOperation];
UIImage *cachedImage = [[[self class] af_sharedImageCache] cachedImageForRequest:urlRequest]; UIImage *cachedImage = [[[self class] af_sharedImageCache] cachedImageForRequest:urlRequest];
if (cachedImage) { if (cachedImage) {
self.image = cachedImage;
self.af_imageRequestOperation = nil;
if (success) { if (success) {
success(nil, nil, cachedImage); success(nil, nil, cachedImage);
} else {
self.image = cachedImage;
} }
} else {
self.image = placeholderImage;
AFImageRequestOperation *requestOperation = [[[AFImageRequestOperation alloc] initWithRequest:urlRequest] autorelease];
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if ([[urlRequest URL] isEqual:[[self.af_imageRequestOperation request] URL]]) {
self.image = responseObject;
self.af_imageRequestOperation = nil;
}
if (success) { self.af_imageRequestOperation = nil;
success(operation.request, operation.response, responseObject); } else {
if (placeholderImage) {
self.image = placeholderImage;
}
AFImageRequestOperation *requestOperation = [[AFImageRequestOperation alloc] initWithRequest:urlRequest];
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if ([urlRequest isEqual:[self.af_imageRequestOperation request]]) {
if (success) {
success(operation.request, operation.response, responseObject);
} else if (responseObject) {
self.image = responseObject;
}
if (self.af_imageRequestOperation == operation) {
self.af_imageRequestOperation = nil;
}
} }
[[[self class] af_sharedImageCache] cacheImage:responseObject forRequest:urlRequest]; [[[self class] af_sharedImageCache] cacheImage:responseObject forRequest:urlRequest];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) { } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if ([[urlRequest URL] isEqual:[[self.af_imageRequestOperation request] URL]]) { if ([urlRequest isEqual:[self.af_imageRequestOperation request]]) {
self.af_imageRequestOperation = nil; if (failure) {
} failure(operation.request, operation.response, error);
}
if (failure) { if (self.af_imageRequestOperation == operation) {
failure(operation.request, operation.response, error); self.af_imageRequestOperation = nil;
}
} }
}]; }];
self.af_imageRequestOperation = requestOperation; self.af_imageRequestOperation = requestOperation;
[[[self class] af_sharedImageRequestOperationQueue] addOperation:self.af_imageRequestOperation]; [[[self class] af_sharedImageRequestOperationQueue] addOperation:self.af_imageRequestOperation];
} }
} }
@ -165,7 +169,7 @@ static inline NSString * AFImageCacheKeyFromURLRequest(NSURLRequest *request) {
default: default:
break; break;
} }
return [self objectForKey:AFImageCacheKeyFromURLRequest(request)]; return [self objectForKey:AFImageCacheKeyFromURLRequest(request)];
} }

View file

@ -4562,7 +4562,8 @@ static NSOperationQueue *sharedQueue = nil;
for (NSNumber *bytes in bandwidthUsageTracker) { for (NSNumber *bytes in bandwidthUsageTracker) {
totalBytes += [bytes unsignedLongValue]; totalBytes += [bytes unsignedLongValue];
} }
averageBandwidthUsedPerSecond = totalBytes/measurements; if (measurements)
averageBandwidthUsedPerSecond = totalBytes/measurements;
} }
+ (unsigned long)averageBandwidthUsedPerSecond + (unsigned long)averageBandwidthUsedPerSecond
@ -4860,7 +4861,7 @@ static NSOperationQueue *sharedQueue = nil;
// RFC 2612 says max-age must override any Expires header // RFC 2612 says max-age must override any Expires header
if (maxAge) { if (maxAge) {
return [[NSDate date] addTimeInterval:maxAge]; return [[NSDate date] dateByAddingTimeInterval:maxAge];
} else { } else {
NSString *expires = [responseHeaders objectForKey:@"Expires"]; NSString *expires = [responseHeaders objectForKey:@"Expires"];
if (expires) { if (expires) {

View file

@ -24,6 +24,7 @@
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
activityLabel = nil; activityLabel = nil;
faviconView = nil; faviconView = nil;
self.separatorInset = UIEdgeInsetsMake(0, 90, 0, 0);
// create favicon and label in view // create favicon and label in view
UIImageView *favicon = [[UIImageView alloc] initWithFrame:CGRectZero]; UIImageView *favicon = [[UIImageView alloc] initWithFrame:CGRectZero];
@ -34,6 +35,7 @@
activity.backgroundColor = [UIColor whiteColor]; activity.backgroundColor = [UIColor whiteColor];
self.activityLabel = activity; self.activityLabel = activity;
[self.contentView addSubview:activity]; [self.contentView addSubview:activity];
topMargin = 15; topMargin = 15;
bottomMargin = 15; bottomMargin = 15;
@ -50,21 +52,21 @@
[super layoutSubviews]; [super layoutSubviews];
// determine outer bounds // determine outer bounds
CGRect contentRect = self.contentView.bounds; [self.activityLabel sizeToFit];
CGRect contentRect = self.frame;
CGRect labelFrame = self.activityLabel.frame;
// position label to bounds // position label to bounds
CGRect labelRect = contentRect; labelFrame.origin.x = leftMargin*2 + avatarSize;
labelRect.origin.x = labelRect.origin.x + leftMargin + avatarSize + leftMargin; labelFrame.origin.y = topMargin - 1;
labelRect.origin.y = labelRect.origin.y + topMargin - 1; labelFrame.size.width = contentRect.size.width - leftMargin - avatarSize - leftMargin - rightMargin - 20;
labelRect.size.width = contentRect.size.width - leftMargin - avatarSize - leftMargin - rightMargin; labelFrame.size.height = contentRect.size.height - topMargin - bottomMargin;
labelRect.size.height = contentRect.size.height - topMargin - bottomMargin; self.activityLabel.frame = labelFrame;
self.activityLabel.frame = labelRect;
[self.activityLabel sizeToFit];
} }
- (int)setActivity:(NSDictionary *)activity withUserProfile:(NSDictionary *)userProfile withWidth:(int)width { - (int)setActivity:(NSDictionary *)activity withUserProfile:(NSDictionary *)userProfile withWidth:(int)width {
// must set the height again for dynamic height in heightForRowAtIndexPath in // must set the height again for dynamic height in heightForRowAtIndexPath in
CGRect activityLabelRect = self.activityLabel.bounds; CGRect activityLabelRect = self.activityLabel.frame;
activityLabelRect.size.width = width - leftMargin - avatarSize - leftMargin - rightMargin; activityLabelRect.size.width = width - leftMargin - avatarSize - leftMargin - rightMargin;
self.activityLabel.frame = activityLabelRect; self.activityLabel.frame = activityLabelRect;
@ -163,13 +165,12 @@
[attrStr addAttributes:@{NSForegroundColorAttributeName:UIColorFromRGB(0x666666)} range:[txtWithTime rangeOfString:comment]]; [attrStr addAttributes:@{NSForegroundColorAttributeName:UIColorFromRGB(0x666666)} range:[txtWithTime rangeOfString:comment]];
[attrStr addAttributes:@{NSForegroundColorAttributeName:UIColorFromRGB(0x999999)} range:[txtWithTime rangeOfString:time]]; [attrStr addAttributes:@{NSForegroundColorAttributeName:UIColorFromRGB(0x999999)} range:[txtWithTime rangeOfString:time]];
[attrStr addAttributes:@{NSFontAttributeName:[UIFont fontWithName:@"Helvetica" size:11]} range:[txtWithTime rangeOfString:time]]; [attrStr addAttributes:@{NSFontAttributeName:[UIFont fontWithName:@"Helvetica" size:11]} range:[txtWithTime rangeOfString:time]];
NSMutableParagraphStyle* style= [NSMutableParagraphStyle new]; NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle defaultParagraphStyle] mutableCopy];
style.lineBreakMode = NSLineBreakByWordWrapping; paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
[attrStr addAttributes:@{NSParagraphStyleAttributeName: style} range:NSMakeRange(0, [txtWithTime length])]; [attrStr addAttributes:@{NSParagraphStyleAttributeName: paragraphStyle} range:NSMakeRange(0, [txtWithTime length])];
NSRange commentRange = [txtWithTime rangeOfString:comment]; NSRange commentRange = [txtWithTime rangeOfString:comment];
if (commentRange.location != NSNotFound) { if (commentRange.location != NSNotFound) {
NSLog(@"Spacing: %@", comment);
commentRange.location -= 2; commentRange.location -= 2;
commentRange.length = 1; commentRange.length = 1;
if ([[txtWithTime substringWithRange:commentRange] isEqualToString:@" "]) { if ([[txtWithTime substringWithRange:commentRange] isEqualToString:@" "]) {

View file

@ -167,12 +167,12 @@
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{ {
int activitesCount = [appDelegate.userActivitiesArray count]; NSInteger activitesCount = [appDelegate.userActivitiesArray count];
return activitesCount + 1; return activitesCount + 1;
} }
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
int activitiesCount = [appDelegate.userActivitiesArray count]; NSInteger activitiesCount = [appDelegate.userActivitiesArray count];
int minimumHeight; int minimumHeight;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
minimumHeight = MINIMUM_ACTIVITY_HEIGHT_IPAD; minimumHeight = MINIMUM_ACTIVITY_HEIGHT_IPAD;
@ -193,9 +193,9 @@
NSMutableDictionary *userProfile = [appDelegate.dictSocialProfile mutableCopy]; NSMutableDictionary *userProfile = [appDelegate.dictSocialProfile mutableCopy];
[userProfile setValue:@"You" forKey:@"username"]; [userProfile setValue:@"You" forKey:@"username"];
NSDictionary *activity = [appDelegate.userActivitiesArray
int height = [activityCell setActivity:[appDelegate.userActivitiesArray objectAtIndex:(indexPath.row)];
objectAtIndex:(indexPath.row)] int height = [activityCell setActivity:activity
withUserProfile:userProfile withUserProfile:userProfile
withWidth:self.frame.size.width - 20]; withWidth:self.frame.size.width - 20];
return height; return height;
@ -220,13 +220,17 @@
// add in loading cell // add in loading cell
return [self makeLoadingCell]; return [self makeLoadingCell];
} else { } else {
NSMutableDictionary *userProfile = [appDelegate.dictSocialProfile mutableCopy]; NSMutableDictionary *userProfile = [appDelegate.dictSocialProfile mutableCopy];
[userProfile setValue:@"You" forKey:@"username"]; [userProfile setValue:@"You" forKey:@"username"];
NSDictionary *activitiy = [appDelegate.userActivitiesArray NSDictionary *activity = [appDelegate.userActivitiesArray
objectAtIndex:(indexPath.row)]; objectAtIndex:(indexPath.row)];
NSString *category = [activitiy objectForKey:@"category"];
[cell setActivity:activity
withUserProfile:userProfile
withWidth:self.frame.size.width - 20];
NSString *category = [activity objectForKey:@"category"];
if ([category isEqualToString:@"follow"]) { if ([category isEqualToString:@"follow"]) {
cell.accessoryType = UITableViewCellAccessoryNone; cell.accessoryType = UITableViewCellAccessoryNone;
} else if ([category isEqualToString:@"signup"]){ } else if ([category isEqualToString:@"signup"]){
@ -239,17 +243,13 @@
UIView *myBackView = [[UIView alloc] initWithFrame:self.frame]; UIView *myBackView = [[UIView alloc] initWithFrame:self.frame];
myBackView.backgroundColor = UIColorFromRGB(NEWSBLUR_HIGHLIGHT_COLOR); myBackView.backgroundColor = UIColorFromRGB(NEWSBLUR_HIGHLIGHT_COLOR);
cell.selectedBackgroundView = myBackView; cell.selectedBackgroundView = myBackView;
// update the cell information
[cell setActivity: activitiy
withUserProfile:userProfile
withWidth:self.frame.size.width - 20];
} }
return cell; return cell;
} }
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
int activitiesCount = [appDelegate.userActivitiesArray count]; NSInteger activitiesCount = [appDelegate.userActivitiesArray count];
if (indexPath.row < activitiesCount) { if (indexPath.row < activitiesCount) {
NSDictionary *activity = [appDelegate.userActivitiesArray objectAtIndex:indexPath.row]; NSDictionary *activity = [appDelegate.userActivitiesArray objectAtIndex:indexPath.row];
NSString *category = [activity objectForKey:@"category"]; NSString *category = [activity objectForKey:@"category"];

View file

@ -64,13 +64,16 @@ static UIFont *indicatorFont = nil;
if (highlighted) { if (highlighted) {
textColor = UIColorFromRGB(0x686868); //0x686868 textColor = UIColorFromRGB(0x686868); //0x686868
} }
[textColor set];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle defaultParagraphStyle] mutableCopy];
paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;
paragraphStyle.alignment = NSTextAlignmentLeft;
[self.siteTitle [self.siteTitle
drawInRect:CGRectMake(leftMargin, 6, rect.size.width - rightMargin, 21) drawInRect:CGRectMake(leftMargin, 6, rect.size.width - rightMargin, 21)
withFont:font withAttributes:@{NSFontAttributeName: font,
lineBreakMode:NSLineBreakByTruncatingTail NSForegroundColorAttributeName: textColor,
alignment:NSTextAlignmentLeft]; NSParagraphStyleAttributeName: paragraphStyle}];
textColor = UIColorFromRGB(0x333333); textColor = UIColorFromRGB(0x333333);
if (highlighted) { if (highlighted) {
@ -89,13 +92,13 @@ static UIFont *indicatorFont = nil;
if (highlighted) { if (highlighted) {
textColor = UIColorFromRGB(0x686868); textColor = UIColorFromRGB(0x686868);
} }
[textColor set];
paragraphStyle.alignment = NSTextAlignmentRight;
[self.siteSubscribers [self.siteSubscribers
drawInRect:CGRectMake(leftMargin + (rect.size.width - rightMargin) / 2 - 10, 42 + adjustForSocial, (rect.size.width - rightMargin) / 2 + 10, 15.0) drawInRect:CGRectMake(leftMargin + (rect.size.width - rightMargin) / 2 - 10, 42 + adjustForSocial, (rect.size.width - rightMargin) / 2 + 10, 15.0)
withFont:font withAttributes:@{NSFontAttributeName: font,
lineBreakMode:NSLineBreakByTruncatingTail NSForegroundColorAttributeName: textColor,
alignment:NSTextAlignmentRight]; NSParagraphStyleAttributeName: paragraphStyle}];
// feed bar // feed bar
CGContextSetStrokeColor(context, CGColorGetComponents([self.feedColorBar CGColor])); CGContextSetStrokeColor(context, CGColorGetComponents([self.feedColorBar CGColor]));

View file

@ -53,18 +53,24 @@
} }
- (void)viewDidLoad { - (void)viewDidLoad {
UIImageView *folderImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"g_icn_folder.png"]]; UIImageView *folderImage = [[UIImageView alloc]
folderImage.frame = CGRectMake(0, 0, 16, 16); initWithImage:[UIImage imageNamed:@"g_icn_folder.png"]];
folderImage.frame = CGRectMake(0, 0, 24, 16);
[folderImage setContentMode:UIViewContentModeRight];
[inFolderInput setLeftView:folderImage]; [inFolderInput setLeftView:folderImage];
[inFolderInput setLeftViewMode:UITextFieldViewModeAlways]; [inFolderInput setLeftViewMode:UITextFieldViewModeAlways];
UIImageView *folderImage2 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"g_icn_folder_rss.png"]]; UIImageView *folderImage2 = [[UIImageView alloc]
folderImage2.frame = CGRectMake(0, 0, 16, 16); initWithImage:[UIImage imageNamed:@"g_icn_folder_rss.png"]];
folderImage2.frame = CGRectMake(0, 0, 24, 16);
[folderImage2 setContentMode:UIViewContentModeRight];
[addFolderInput setLeftView:folderImage2]; [addFolderInput setLeftView:folderImage2];
[addFolderInput setLeftViewMode:UITextFieldViewModeAlways]; [addFolderInput setLeftViewMode:UITextFieldViewModeAlways];
UIImageView *urlImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"world.png"]]; UIImageView *urlImage = [[UIImageView alloc]
urlImage.frame = CGRectMake(0, 0, 16, 16); initWithImage:[UIImage imageNamed:@"world.png"]];
urlImage.frame = CGRectMake(0, 0, 24, 16);
[urlImage setContentMode:UIViewContentModeRight];
[siteAddressInput setLeftView:urlImage]; [siteAddressInput setLeftView:urlImage];
[siteAddressInput setLeftViewMode:UITextFieldViewModeAlways]; [siteAddressInput setLeftViewMode:UITextFieldViewModeAlways];
@ -185,7 +191,7 @@
return; return;
} }
int periodLoc = [phrase rangeOfString:@"."].location; NSInteger periodLoc = [phrase rangeOfString:@"."].location;
if (periodLoc != NSNotFound && siteAddressInput.returnKeyType != UIReturnKeyDone) { if (periodLoc != NSNotFound && siteAddressInput.returnKeyType != UIReturnKeyDone) {
// URL // URL
[siteAddressInput setReturnKeyType:UIReturnKeyDone]; [siteAddressInput setReturnKeyType:UIReturnKeyDone];
@ -302,11 +308,11 @@
- (NSString *)extractParentFolder { - (NSString *)extractParentFolder {
NSString *parent_folder = [inFolderInput text]; NSString *parent_folder = [inFolderInput text];
int folder_loc = [parent_folder rangeOfString:@" - " options:NSBackwardsSearch].location; NSInteger folder_loc = [parent_folder rangeOfString:@" - " options:NSBackwardsSearch].location;
if ([parent_folder length] && folder_loc != NSNotFound) { if ([parent_folder length] && folder_loc != NSNotFound) {
parent_folder = [parent_folder substringFromIndex:(folder_loc + 3)]; parent_folder = [parent_folder substringFromIndex:(folder_loc + 3)];
} }
int top_level_loc = [parent_folder rangeOfString:@" Top Level " options:NSBackwardsSearch].location; NSInteger top_level_loc = [parent_folder rangeOfString:@" Top Level " options:NSBackwardsSearch].location;
if (parent_folder.length && top_level_loc != NSNotFound) { if (parent_folder.length && top_level_loc != NSNotFound) {
parent_folder = @""; parent_folder = @"";
} }
@ -425,7 +431,7 @@ numberOfRowsInComponent:(NSInteger)component {
#pragma mark Autocomplete sites #pragma mark Autocomplete sites
- (int)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [autocompleteResults count]; return [autocompleteResults count];
} }

View file

@ -66,7 +66,7 @@
action: @selector(doCancelButton)]; action: @selector(doCancelButton)];
self.navigationItem.leftBarButtonItem = cancelButton; self.navigationItem.leftBarButtonItem = cancelButton;
self.view.frame = CGRectMake(0, 0, 320, 416); self.view.frame = CGRectMake(0, 0, 320, 416);
self.contentSizeForViewInPopover = self.view.frame.size; self.preferredContentSize = self.view.frame.size;
} }
} }

View file

@ -20,3 +20,4 @@
- (void)informLoadingMessage:(NSString *)message; - (void)informLoadingMessage:(NSString *)message;
@end @end

View file

@ -19,7 +19,7 @@
ActivityModule *activitiesModule; ActivityModule *activitiesModule;
UIWebView *feedbackWebView; UIWebView *feedbackWebView;
UIToolbar *toolbar; UIToolbar *toolbar;
UIToolbar *topToolbar; UINavigationBar *topToolbar;
UISegmentedControl *segmentedButton; UISegmentedControl *segmentedButton;
} }
@ -28,7 +28,7 @@
@property (nonatomic) IBOutlet ActivityModule *activitiesModule; @property (nonatomic) IBOutlet ActivityModule *activitiesModule;
@property (nonatomic) IBOutlet UIWebView *feedbackWebView; @property (nonatomic) IBOutlet UIWebView *feedbackWebView;
@property (nonatomic) IBOutlet UIToolbar *topToolbar; @property (nonatomic) IBOutlet UINavigationBar *topToolbar;
@property (nonatomic) IBOutlet UIToolbar *toolbar; @property (nonatomic) IBOutlet UIToolbar *toolbar;
@property (nonatomic) IBOutlet UISegmentedControl *segmentedButton; @property (nonatomic) IBOutlet UISegmentedControl *segmentedButton;

View file

@ -42,11 +42,14 @@
self.feedbackWebView.delegate = self; self.feedbackWebView.delegate = self;
self.segmentedButton.selectedSegmentIndex = 0; self.segmentedButton.selectedSegmentIndex = 0;
self.topToolbar.tintColor = [UIColor colorWithRed:0.16f green:0.36f blue:0.46 alpha:0.9];
// preload feedback // preload feedback
self.feedbackWebView.scalesPageToFit = YES; self.feedbackWebView.scalesPageToFit = YES;
[self.segmentedButton
setTitleTextAttributes:@{NSFontAttributeName:
[UIFont fontWithName:@"Helvetica-Bold" size:11.0f]}
forState:UIControlStateNormal];
NSString *urlAddress = FEEDBACK_URL; NSString *urlAddress = FEEDBACK_URL;
//Create a URL object. //Create a URL object.
NSURL *url = [NSURL URLWithString:urlAddress]; NSURL *url = [NSURL URLWithString:urlAddress];
@ -54,7 +57,10 @@
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url]; NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
//Load the request in the UIWebView. //Load the request in the UIWebView.
[self.feedbackWebView loadRequest:requestObj]; [self.feedbackWebView loadRequest:requestObj];
CGRect topToolbarFrame = self.topToolbar.frame;
topToolbarFrame.size.height += 20;
self.topToolbar.frame = topToolbarFrame;
} }
- (void)viewDidUnload { - (void)viewDidUnload {
@ -86,7 +92,7 @@
# pragma mark Navigation # pragma mark Navigation
- (IBAction)tapSegmentedButton:(id)sender { - (IBAction)tapSegmentedButton:(id)sender {
int selectedSegmentIndex = [self.segmentedButton selectedSegmentIndex]; NSInteger selectedSegmentIndex = [self.segmentedButton selectedSegmentIndex];
if (selectedSegmentIndex == 0) { if (selectedSegmentIndex == 0) {
self.interactionsModule.hidden = NO; self.interactionsModule.hidden = NO;

View file

@ -51,11 +51,23 @@
- (void)viewWillAppear:(BOOL)animated { - (void)viewWillAppear:(BOOL)animated {
[self.menuTableView reloadData]; [self.menuTableView reloadData];
[orderSegmentedControl
setTitleTextAttributes:@{NSFontAttributeName:
[UIFont fontWithName:@"Helvetica-Bold" size:11.0f]}
forState:UIControlStateNormal];
[orderSegmentedControl setContentOffset:CGSizeMake(0, 1) forSegmentAtIndex:0];
[orderSegmentedControl setContentOffset:CGSizeMake(0, 1) forSegmentAtIndex:1];
[orderSegmentedControl setSelectedSegmentIndex:0]; [orderSegmentedControl setSelectedSegmentIndex:0];
if ([appDelegate.activeOrder isEqualToString:@"oldest"]) { if ([appDelegate.activeOrder isEqualToString:@"oldest"]) {
[orderSegmentedControl setSelectedSegmentIndex:1]; [orderSegmentedControl setSelectedSegmentIndex:1];
} }
[readFilterSegmentedControl
setTitleTextAttributes:@{NSFontAttributeName:
[UIFont fontWithName:@"Helvetica-Bold" size:11.0f]}
forState:UIControlStateNormal];
[readFilterSegmentedControl setContentOffset:CGSizeMake(0, 1) forSegmentAtIndex:0];
[readFilterSegmentedControl setContentOffset:CGSizeMake(0, 1) forSegmentAtIndex:1];
[readFilterSegmentedControl setSelectedSegmentIndex:0]; [readFilterSegmentedControl setSelectedSegmentIndex:0];
if ([appDelegate.activeReadFilter isEqualToString:@"unread"]) { if ([appDelegate.activeReadFilter isEqualToString:@"unread"]) {
[readFilterSegmentedControl setSelectedSegmentIndex:1]; [readFilterSegmentedControl setSelectedSegmentIndex:1];
@ -147,7 +159,7 @@
return cell; return cell;
} }
- (float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return kMenuOptionHeight; return kMenuOptionHeight;
} }
@ -185,6 +197,7 @@
UITableViewCell *cell = [[UITableViewCell alloc] init]; UITableViewCell *cell = [[UITableViewCell alloc] init];
cell.frame = CGRectMake(0, 0, 240, kMenuOptionHeight); cell.frame = CGRectMake(0, 0, 240, kMenuOptionHeight);
cell.selectionStyle = UITableViewCellSelectionStyleNone; cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.separatorInset = UIEdgeInsetsZero;
orderSegmentedControl.frame = CGRectMake(8, 7, cell.frame.size.width - 8*2, orderSegmentedControl.frame = CGRectMake(8, 7, cell.frame.size.width - 8*2,
kMenuOptionHeight - 7*2); kMenuOptionHeight - 7*2);
@ -200,6 +213,8 @@
UITableViewCell *cell = [[UITableViewCell alloc] init]; UITableViewCell *cell = [[UITableViewCell alloc] init];
cell.frame = CGRectMake(0, 0, 240, kMenuOptionHeight); cell.frame = CGRectMake(0, 0, 240, kMenuOptionHeight);
cell.selectionStyle = UITableViewCellSelectionStyleNone; cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.separatorInset = UIEdgeInsetsZero;
readFilterSegmentedControl.frame = CGRectMake(8, 7, cell.frame.size.width - 8*2, readFilterSegmentedControl.frame = CGRectMake(8, 7, cell.frame.size.width - 8*2,
kMenuOptionHeight - 7*2); kMenuOptionHeight - 7*2);
[readFilterSegmentedControl setTitle:[@"All stories" uppercaseString] forSegmentAtIndex:0]; [readFilterSegmentedControl setTitle:[@"All stories" uppercaseString] forSegmentAtIndex:0];

View file

@ -8,15 +8,16 @@
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import "NewsBlurAppDelegate.h" #import "NewsBlurAppDelegate.h"
#import "ABTableViewCell.h" #import "NBSwipeableCell.h"
@interface FeedDetailTableCell : ABTableViewCell { @interface FeedDetailTableCell : NBSwipeableCell {
NewsBlurAppDelegate *appDelegate; NewsBlurAppDelegate *appDelegate;
// All views // All views
NSString *storyTitle; NSString *storyTitle;
NSString *storyAuthor; NSString *storyAuthor;
NSString *storyDate; NSString *storyDate;
NSInteger storyTimestamp;
int storyScore; int storyScore;
BOOL isStarred; BOOL isStarred;
BOOL isShared; BOOL isShared;
@ -31,18 +32,20 @@
UIColor *feedColorBar; UIColor *feedColorBar;
UIColor *feedColorBarTopBorder; UIColor *feedColorBarTopBorder;
UIView *cellContent;
} }
@property (nonatomic) NSString *siteTitle; @property (nonatomic) NSString *siteTitle;
@property (nonatomic) UIImage *siteFavicon; @property (nonatomic) UIImage *siteFavicon;
@property (readwrite) int storyScore; @property (readwrite) int storyScore;
@property (readwrite) BOOL isStarred; @property (nonatomic, readwrite) BOOL isStarred;
@property (readwrite) BOOL isShared; @property (readwrite) BOOL isShared;
@property (nonatomic) NSString *storyTitle; @property (nonatomic) NSString *storyTitle;
@property (nonatomic) NSString *storyAuthor; @property (nonatomic) NSString *storyAuthor;
@property (nonatomic) NSString *storyDate; @property (nonatomic) NSString *storyDate;
@property (nonatomic) NSInteger storyTimestamp;
@property (nonatomic) UIColor *feedColorBar; @property (nonatomic) UIColor *feedColorBar;
@property (nonatomic) UIColor *feedColorBarTopBorder; @property (nonatomic) UIColor *feedColorBarTopBorder;
@ -52,6 +55,12 @@
@property (readwrite) BOOL isRiverOrSocial; @property (readwrite) BOOL isRiverOrSocial;
@property (readwrite) BOOL hasAlpha; @property (readwrite) BOOL hasAlpha;
- (UIImage *)imageByApplyingAlpha:(UIImage *)image withAlpha:(CGFloat) alpha; - (void)setupGestures;
@end @end
@interface FeedDetailTableCellView : UIView
@property (nonatomic) FeedDetailTableCell *cell;
@end

View file

@ -11,22 +11,25 @@
#import "ABTableViewCell.h" #import "ABTableViewCell.h"
#import "UIView+TKCategory.h" #import "UIView+TKCategory.h"
#import "Utilities.h" #import "Utilities.h"
#import "MCSwipeTableViewCell.h"
static UIFont *textFont = nil; static UIFont *textFont = nil;
static UIFont *indicatorFont = nil; static UIFont *indicatorFont = nil;
@class FeedDetailViewController;
@implementation FeedDetailTableCell @implementation FeedDetailTableCell
@synthesize storyTitle; @synthesize storyTitle;
@synthesize storyAuthor; @synthesize storyAuthor;
@synthesize storyDate; @synthesize storyDate;
@synthesize storyTimestamp;
@synthesize storyScore; @synthesize storyScore;
@synthesize siteTitle; @synthesize siteTitle;
@synthesize siteFavicon; @synthesize siteFavicon;
@synthesize isRead; @synthesize isRead;
@synthesize isStarred;
@synthesize isShared; @synthesize isShared;
@synthesize isStarred;
@synthesize isShort; @synthesize isShort;
@synthesize isRiverOrSocial; @synthesize isRiverOrSocial;
@synthesize feedColorBar; @synthesize feedColorBar;
@ -45,35 +48,82 @@ static UIFont *indicatorFont = nil;
} }
} }
- (void)drawContentView:(CGRect)r highlighted:(BOOL)highlighted { - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
cellContent = [[FeedDetailTableCellView alloc] initWithFrame:self.frame];
int adjustForSocial = 3; cellContent.opaque = YES;
if (self.isRiverOrSocial) { [self.contentView addSubview:cellContent];
adjustForSocial = 20;
} }
return self;
}
- (void)drawRect:(CGRect)rect {
((FeedDetailTableCellView *)cellContent).cell = self;
cellContent.frame = rect;
[cellContent setNeedsDisplay];
}
- (void)setupGestures {
NSString *unreadIcon;
if (storyScore == -1) {
unreadIcon = @"g_icn_hidden.png";
} else if (storyScore == 1) {
unreadIcon = @"g_icn_focus.png";
} else {
unreadIcon = @"g_icn_unread.png";
}
UIColor *shareColor = self.isStarred ?
UIColorFromRGB(0xF69E89) :
UIColorFromRGB(0xA4D97B);
UIColor *readColor = self.isRead ?
UIColorFromRGB(0xBED49F) :
UIColorFromRGB(0xFFFFD2);
appDelegate = [NewsBlurAppDelegate sharedAppDelegate];
[self setDelegate:(FeedDetailViewController <MCSwipeTableViewCellDelegate> *)appDelegate.feedDetailViewController];
[self setFirstStateIconName:@"clock.png"
firstColor:shareColor
secondStateIconName:nil
secondColor:nil
thirdIconName:unreadIcon
thirdColor:readColor
fourthIconName:nil
fourthColor:nil];
self.mode = MCSwipeTableViewCellModeSwitch;
self.shouldAnimatesIcons = NO;
}
@end
@implementation FeedDetailTableCellView
@synthesize cell;
- (void)drawRect:(CGRect)r {
int adjustForSocial = 3;
if (cell.isRiverOrSocial) {
adjustForSocial = 20;
}
CGContextRef context = UIGraphicsGetCurrentContext(); CGContextRef context = UIGraphicsGetCurrentContext();
CGRect rect = CGRectInset(r, 12, 12); CGRect rect = CGRectInset(r, 12, 12);
rect.size.width -= 18; // Scrollbar padding rect.size.width -= 18; // Scrollbar padding
if (!highlighted) { UIColor *backgroundColor;
UIColor *backgroundColor; backgroundColor = cell.highlighted || cell.selected ?
backgroundColor = UIColorFromRGB(0xf4f4f4); UIColorFromRGB(0xFFFDEF) : UIColorFromRGB(0xf4f4f4);
[backgroundColor set]; [backgroundColor set];
}
CGContextFillRect(context, r); CGContextFillRect(context, r);
if (highlighted) {
[NewsBlurAppDelegate fillGradient:r startColor:UIColorFromRGB(0xFFFDEF) endColor:UIColorFromRGB(0xFFFDDF)];
}
UIColor *textColor; UIColor *textColor;
UIFont *font; UIFont *font;
if (self.isRead) { if (cell.isRead) {
font = [UIFont fontWithName:@"Helvetica" size:11]; font = [UIFont fontWithName:@"Helvetica" size:11];
textColor = UIColorFromRGB(0x808080); textColor = UIColorFromRGB(0x808080);
} else { } else {
@ -81,19 +131,21 @@ static UIFont *indicatorFont = nil;
textColor = UIColorFromRGB(0x606060); textColor = UIColorFromRGB(0x606060);
} }
if (highlighted) { if (cell.highlighted || cell.selected) {
textColor = UIColorFromRGB(0x686868); textColor = UIColorFromRGB(0x686868);
} }
[textColor set];
if (self.isRiverOrSocial) { NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle defaultParagraphStyle] mutableCopy];
[self.siteTitle paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
drawInRect:CGRectMake(leftMargin + 20, 7, rect.size.width - 20, 21) paragraphStyle.alignment = NSTextAlignmentLeft;
withFont:font
lineBreakMode:NSLineBreakByTruncatingTail if (cell.isRiverOrSocial) {
alignment:NSTextAlignmentLeft]; [cell.siteTitle drawInRect:CGRectMake(leftMargin + 20, 7, rect.size.width - 20, 21)
withAttributes:@{NSFontAttributeName: font,
NSForegroundColorAttributeName: textColor,
NSParagraphStyleAttributeName: paragraphStyle}];
if (self.isRead) { if (cell.isRead) {
font = [UIFont fontWithName:@"Helvetica" size:12]; font = [UIFont fontWithName:@"Helvetica" size:12];
textColor = UIColorFromRGB(0x606060); textColor = UIColorFromRGB(0x606060);
@ -101,63 +153,65 @@ static UIFont *indicatorFont = nil;
textColor = UIColorFromRGB(0x333333); textColor = UIColorFromRGB(0x333333);
font = [UIFont fontWithName:@"Helvetica-Bold" size:12]; font = [UIFont fontWithName:@"Helvetica-Bold" size:12];
} }
if (highlighted) { if (cell.highlighted || cell.selected) {
textColor = UIColorFromRGB(0x686868); textColor = UIColorFromRGB(0x686868);
} }
[textColor set];
} }
// story title // story title
CGSize theSize = [cell.storyTitle
CGSize theSize = [self.storyTitle sizeWithFont:font constrainedToSize:CGSizeMake(rect.size.width, 30.0) lineBreakMode:NSLineBreakByTruncatingTail]; boundingRectWithSize:CGSizeMake(rect.size.width, cell.isShort ? 15.0 : 30.0)
options:NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName: font,
NSParagraphStyleAttributeName: paragraphStyle}
context:nil].size;
int storyTitleY = 7 + adjustForSocial + ((30 - theSize.height)/2); int storyTitleY = 7 + adjustForSocial + ((30 - theSize.height)/2);
if (self.isShort) { if (cell.isShort) {
storyTitleY = 7 + adjustForSocial + 2; storyTitleY = 7 + adjustForSocial + 2;
} }
int storyTitleX = leftMargin; int storyTitleX = leftMargin;
if (self.isStarred) { if (cell.isStarred) {
UIImage *savedIcon = [UIImage imageNamed:@"clock"]; UIImage *savedIcon = [UIImage imageNamed:@"clock"];
[savedIcon drawInRect:CGRectMake(storyTitleX, storyTitleY - 1, 16, 16) blendMode:nil alpha:1]; [savedIcon drawInRect:CGRectMake(storyTitleX, storyTitleY - 1, 16, 16) blendMode:nil alpha:1];
storyTitleX += 20; storyTitleX += 20;
} }
if (self.isShared) { if (cell.isShared) {
UIImage *savedIcon = [UIImage imageNamed:@"menu_icn_share"]; UIImage *savedIcon = [UIImage imageNamed:@"menu_icn_share"];
[savedIcon drawInRect:CGRectMake(storyTitleX, storyTitleY - 1, 16, 16) blendMode:nil alpha:1]; [savedIcon drawInRect:CGRectMake(storyTitleX, storyTitleY - 1, 16, 16) blendMode:nil alpha:1];
storyTitleX += 20; storyTitleX += 20;
} }
[self.storyTitle [cell.storyTitle drawWithRect:CGRectMake(storyTitleX, storyTitleY, rect.size.width - storyTitleX + leftMargin, theSize.height)
drawInRect:CGRectMake(storyTitleX, storyTitleY, rect.size.width - storyTitleX + leftMargin, theSize.height) options:NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesLineFragmentOrigin
withFont:font attributes:@{NSFontAttributeName: font,
lineBreakMode:NSLineBreakByTruncatingTail NSForegroundColorAttributeName: textColor,
alignment:NSTextAlignmentLeft]; NSParagraphStyleAttributeName: paragraphStyle}
context:nil];
int storyAuthorDateY = 41 + adjustForSocial; int storyAuthorDateY = 41 + adjustForSocial;
if (self.isShort) { if (cell.isShort) {
storyAuthorDateY -= 13; storyAuthorDateY -= 13;
} }
// story author style // story author style
if (self.isRead) { if (cell.isRead) {
textColor = UIColorFromRGB(0x808080); textColor = UIColorFromRGB(0x959595);
font = [UIFont fontWithName:@"Helvetica" size:10]; font = [UIFont fontWithName:@"Helvetica" size:10];
} else { } else {
textColor = UIColorFromRGB(0x959595); textColor = UIColorFromRGB(0xA6A8A2);
font = [UIFont fontWithName:@"Helvetica-Bold" size:10]; font = [UIFont fontWithName:@"Helvetica-Bold" size:10];
} }
if (highlighted) { if (cell.highlighted || cell.selected) {
textColor = UIColorFromRGB(0x686868); textColor = UIColorFromRGB(0x959595);
} }
[textColor set];
[cell.storyAuthor
[self.storyAuthor
drawInRect:CGRectMake(leftMargin, storyAuthorDateY, (rect.size.width) / 2 - 10, 15.0) drawInRect:CGRectMake(leftMargin, storyAuthorDateY, (rect.size.width) / 2 - 10, 15.0)
withFont:font withAttributes:@{NSFontAttributeName: font,
lineBreakMode:NSLineBreakByTruncatingTail NSForegroundColorAttributeName: textColor,
alignment:NSTextAlignmentLeft]; NSParagraphStyleAttributeName: paragraphStyle}];
// story date // story date
if (self.isRead) { if (cell.isRead) {
textColor = UIColorFromRGB(0xbabdd1); textColor = UIColorFromRGB(0xbabdd1);
font = [UIFont fontWithName:@"Helvetica" size:10]; font = [UIFont fontWithName:@"Helvetica" size:10];
} else { } else {
@ -165,118 +219,108 @@ static UIFont *indicatorFont = nil;
font = [UIFont fontWithName:@"Helvetica-Bold" size:10]; font = [UIFont fontWithName:@"Helvetica-Bold" size:10];
} }
if (highlighted) { if (cell.highlighted || cell.selected) {
textColor = UIColorFromRGB(0x686868); if (cell.isRead) {
textColor = UIColorFromRGB(0xaaadc1);
} else {
textColor = UIColorFromRGB(0x5a5d91);
}
} }
[textColor set];
[self.storyDate
drawInRect:CGRectMake(leftMargin + (rect.size.width) / 2 - 10, storyAuthorDateY, (rect.size.width) / 2 + 10, 15.0)
withFont:font
lineBreakMode:NSLineBreakByTruncatingTail
alignment:NSTextAlignmentRight];
paragraphStyle.alignment = NSTextAlignmentRight;
NSString *date = [Utilities formatShortDateFromTimestamp:cell.storyTimestamp];
[date
drawInRect:CGRectMake(leftMargin + (rect.size.width) / 2 - 10, storyAuthorDateY, (rect.size.width) / 2 + 10, 15.0)
withAttributes:@{NSFontAttributeName: font,
NSForegroundColorAttributeName: textColor,
NSParagraphStyleAttributeName: paragraphStyle}];
// feed bar // feed bar
CGContextSetStrokeColor(context, CGColorGetComponents([self.feedColorBarTopBorder CGColor])); CGContextSetStrokeColor(context, CGColorGetComponents([cell.feedColorBarTopBorder CGColor]));
if (self.isRead) { if (cell.isRead) {
CGContextSetAlpha(context, 0.15); CGContextSetAlpha(context, 0.15);
} }
CGContextSetLineWidth(context, 4.0f); CGContextSetLineWidth(context, 4.0f);
CGContextBeginPath(context); CGContextBeginPath(context);
CGContextMoveToPoint(context, 2.0f, 1.0f); CGContextMoveToPoint(context, 2.0f, 0);
CGContextAddLineToPoint(context, 2.0f, self.frame.size.height - 1); CGContextAddLineToPoint(context, 2.0f, cell.frame.size.height);
CGContextStrokePath(context); CGContextStrokePath(context);
CGContextSetStrokeColor(context, CGColorGetComponents([self.feedColorBar CGColor])); CGContextSetStrokeColor(context, CGColorGetComponents([cell.feedColorBar CGColor]));
CGContextBeginPath(context); CGContextBeginPath(context);
CGContextMoveToPoint(context, 6.0f, 1.0f); CGContextMoveToPoint(context, 6.0f, 0);
CGContextAddLineToPoint(context, 6.0, self.frame.size.height - 1); CGContextAddLineToPoint(context, 6.0, cell.frame.size.height);
CGContextStrokePath(context); CGContextStrokePath(context);
// reset for borders // reset for borders
UIColor *white = UIColorFromRGB(0xffffff);
CGContextSetAlpha(context, 1.0); CGContextSetAlpha(context, 1.0);
CGContextSetLineWidth(context, 1.0f); if (cell.highlighted || cell.selected) {
if (highlighted) {
// top border // top border
UIColor *blue = UIColorFromRGB(0xF9F8F4); CGContextSetStrokeColor(context, CGColorGetComponents([white CGColor]));
CGContextSetLineWidth(context, 1.0f);
CGContextBeginPath(context);
CGContextMoveToPoint(context, 0, 0.5f);
CGContextAddLineToPoint(context, cell.bounds.size.width, 0.5f);
CGContextStrokePath(context);
CGFloat lineWidth = 0.5f;
CGContextSetLineWidth(context, lineWidth);
UIColor *blue = UIColorFromRGB(0xDFDDCF);
CGContextSetStrokeColor(context, CGColorGetComponents([blue CGColor])); CGContextSetStrokeColor(context, CGColorGetComponents([blue CGColor]));
CGContextBeginPath(context); CGContextBeginPath(context);
CGContextMoveToPoint(context, 0, 0.5f); CGContextMoveToPoint(context, 0, 1.0f + 0.5f*lineWidth);
CGContextAddLineToPoint(context, self.bounds.size.width, 0.5f); CGContextAddLineToPoint(context, cell.bounds.size.width, 1.0f + 0.5f*lineWidth);
CGContextStrokePath(context); CGContextStrokePath(context);
// bottom border // bottom border
CGContextBeginPath(context); CGContextBeginPath(context);
CGContextMoveToPoint(context, 0, self.bounds.size.height - 1.5f); CGContextMoveToPoint(context, 0, cell.bounds.size.height - .5f*lineWidth);
CGContextAddLineToPoint(context, self.bounds.size.width, self.bounds.size.height - 1.5f); CGContextAddLineToPoint(context, cell.bounds.size.width, cell.bounds.size.height - .5f*lineWidth);
CGContextStrokePath(context); CGContextStrokePath(context);
} else { } else {
// top border // top border
UIColor *white = UIColorFromRGB(0xffffff); CGContextSetLineWidth(context, 1.0f);
CGContextSetStrokeColor(context, CGColorGetComponents([white CGColor])); CGContextSetStrokeColor(context, CGColorGetComponents([white CGColor]));
CGContextBeginPath(context); CGContextBeginPath(context);
CGContextMoveToPoint(context, 0.0f, 0.5f); CGContextMoveToPoint(context, 0.0f, 0.5f);
CGContextAddLineToPoint(context, self.bounds.size.width, 0.5f); CGContextAddLineToPoint(context, cell.bounds.size.width, 0.5f);
CGContextStrokePath(context); CGContextStrokePath(context);
} }
// site favicon // site favicon
if (self.isRead && !self.hasAlpha) { if (cell.isRead && !cell.hasAlpha) {
if (self.isRiverOrSocial) { if (cell.isRiverOrSocial) {
self.siteFavicon = [self imageByApplyingAlpha:self.siteFavicon withAlpha:0.25]; cell.siteFavicon = [cell imageByApplyingAlpha:cell.siteFavicon withAlpha:0.25];
} }
self.hasAlpha = YES; cell.hasAlpha = YES;
} }
if (self.isRiverOrSocial) { if (cell.isRiverOrSocial) {
[self.siteFavicon drawInRect:CGRectMake(leftMargin, 6.0, 16.0, 16.0)]; [cell.siteFavicon drawInRect:CGRectMake(leftMargin, 6.0, 16.0, 16.0)];
} }
// story indicator // story indicator
int storyIndicatorY = 4 + adjustForSocial; int storyIndicatorY = 4 + adjustForSocial;
if (self.isShort){ if (cell.isShort){
storyIndicatorY = 4 + adjustForSocial - 5 ; storyIndicatorY = 4 + adjustForSocial - 5 ;
} }
UIImage *unreadIcon; UIImage *unreadIcon;
if (storyScore == -1) { if (cell.storyScore == -1) {
unreadIcon = [UIImage imageNamed:@"g_icn_hidden"]; unreadIcon = [UIImage imageNamed:@"g_icn_hidden"];
} else if (storyScore == 1) { } else if (cell.storyScore == 1) {
unreadIcon = [UIImage imageNamed:@"g_icn_focus"]; unreadIcon = [UIImage imageNamed:@"g_icn_focus"];
} else { } else {
unreadIcon = [UIImage imageNamed:@"g_icn_unread"]; unreadIcon = [UIImage imageNamed:@"g_icn_unread"];
} }
[unreadIcon drawInRect:CGRectMake(15, storyIndicatorY + 14, 8, 8) blendMode:nil alpha:(self.isRead ? .15 : 1)]; [unreadIcon drawInRect:CGRectMake(15, storyIndicatorY + 14, 8, 8) blendMode:nil alpha:(cell.isRead ? .15 : 1)];
} }
- (UIImage *)imageByApplyingAlpha:(UIImage *)image withAlpha:(CGFloat) alpha { @end
UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0f);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGRect area = CGRectMake(0, 0, image.size.width, image.size.height);
CGContextScaleCTM(ctx, 1, -1);
CGContextTranslateCTM(ctx, 0, -area.size.height);
CGContextSetBlendMode(ctx, kCGBlendModeMultiply);
CGContextSetAlpha(ctx, alpha);
CGContextDrawImage(ctx, area, image.CGImage);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
@end

View file

@ -12,17 +12,19 @@
#import "BaseViewController.h" #import "BaseViewController.h"
#import "Utilities.h" #import "Utilities.h"
#import "WEPopoverController.h" #import "WEPopoverController.h"
#import "TransparentToolbar.h"
#import "NBNotifier.h" #import "NBNotifier.h"
#import "MCSwipeTableViewCell.h"
@class NewsBlurAppDelegate; @class NewsBlurAppDelegate;
@class FeedDetailTableCell; @class FeedDetailTableCell;
@class MCSwipeTableViewCell;
@interface FeedDetailViewController : BaseViewController @interface FeedDetailViewController : BaseViewController
<UITableViewDelegate, UITableViewDataSource, <UITableViewDelegate, UITableViewDataSource,
UIActionSheetDelegate, UIAlertViewDelegate, UIActionSheetDelegate, UIAlertViewDelegate,
UIPopoverControllerDelegate, ASIHTTPRequestDelegate, UIPopoverControllerDelegate, ASIHTTPRequestDelegate,
WEPopoverControllerDelegate> { WEPopoverControllerDelegate, MCSwipeTableViewCellDelegate,
UIGestureRecognizerDelegate> {
NewsBlurAppDelegate *appDelegate; NewsBlurAppDelegate *appDelegate;
int feedPage; int feedPage;
@ -45,10 +47,8 @@
@property (nonatomic) IBOutlet UIBarButtonItem * settingsBarButton; @property (nonatomic) IBOutlet UIBarButtonItem * settingsBarButton;
@property (nonatomic) IBOutlet UIBarButtonItem * spacerBarButton; @property (nonatomic) IBOutlet UIBarButtonItem * spacerBarButton;
@property (nonatomic) IBOutlet UIBarButtonItem * spacer2BarButton; @property (nonatomic) IBOutlet UIBarButtonItem * spacer2BarButton;
@property (nonatomic) IBOutlet UIBarButtonItem * spacer3BarButton;
@property (nonatomic) IBOutlet UIBarButtonItem * separatorBarButton; @property (nonatomic) IBOutlet UIBarButtonItem * separatorBarButton;
@property (nonatomic) IBOutlet UIBarButtonItem * titleImageBarButton; @property (nonatomic) IBOutlet UIBarButtonItem * titleImageBarButton;
@property (nonatomic) IBOutlet TransparentToolbar * rightToolbar;
@property (nonatomic, retain) WEPopoverController *popoverController; @property (nonatomic, retain) WEPopoverController *popoverController;
@property (nonatomic, retain) NBNotifier *notifier; @property (nonatomic, retain) NBNotifier *notifier;
@ -76,6 +76,7 @@
- (void)setUserAvatarLayout:(UIInterfaceOrientation)orientation; - (void)setUserAvatarLayout:(UIInterfaceOrientation)orientation;
- (void)fadeSelectedCell; - (void)fadeSelectedCell;
- (void)loadStory:(FeedDetailTableCell *)cell atRow:(NSInteger)row;
- (void)redrawUnreadStory; - (void)redrawUnreadStory;
- (IBAction)doOpenMarkReadActionSheet:(id)sender; - (IBAction)doOpenMarkReadActionSheet:(id)sender;
- (IBAction)doOpenSettingsActionSheet:(id)sender; - (IBAction)doOpenSettingsActionSheet:(id)sender;

View file

@ -24,11 +24,12 @@
#import "UIBarButtonItem+WEPopover.h" #import "UIBarButtonItem+WEPopover.h"
#import "WEPopoverController.h" #import "WEPopoverController.h"
#import "UIBarButtonItem+Image.h" #import "UIBarButtonItem+Image.h"
#import "TransparentToolbar.h"
#import "FeedDetailMenuViewController.h" #import "FeedDetailMenuViewController.h"
#import "NBNotifier.h" #import "NBNotifier.h"
#import "NBLoadingCell.h" #import "NBLoadingCell.h"
#import "FMDatabase.h" #import "FMDatabase.h"
#import "NBBarButtonItem.h"
#import "UIActivitiesControl.h"
#define kTableViewRowHeight 61; #define kTableViewRowHeight 61;
#define kTableViewRiverRowHeight 81; #define kTableViewRiverRowHeight 81;
@ -49,8 +50,7 @@
@synthesize settingsBarButton; @synthesize settingsBarButton;
@synthesize separatorBarButton; @synthesize separatorBarButton;
@synthesize titleImageBarButton; @synthesize titleImageBarButton;
@synthesize spacerBarButton, spacer2BarButton, spacer3BarButton; @synthesize spacerBarButton, spacer2BarButton;
@synthesize rightToolbar;
@synthesize appDelegate; @synthesize appDelegate;
@synthesize feedPage; @synthesize feedPage;
@synthesize pageFetching; @synthesize pageFetching;
@ -75,18 +75,12 @@
self.storyTitlesTable.backgroundColor = UIColorFromRGB(0xf4f4f4); self.storyTitlesTable.backgroundColor = UIColorFromRGB(0xf4f4f4);
self.storyTitlesTable.separatorColor = UIColorFromRGB(0xE9E8E4); self.storyTitlesTable.separatorColor = UIColorFromRGB(0xE9E8E4);
rightToolbar = [[TransparentToolbar alloc]
initWithFrame:CGRectMake(0, 0, 76, 44)];
spacerBarButton = [[UIBarButtonItem alloc] spacerBarButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
spacerBarButton.width = -12; spacerBarButton.width = 0;
spacer2BarButton = [[UIBarButtonItem alloc] spacer2BarButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
spacer2BarButton.width = -10; spacer2BarButton.width = 0;
spacer3BarButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
spacer3BarButton.width = -10;
UIImage *separatorImage = [UIImage imageNamed:@"bar-separator.png"]; UIImage *separatorImage = [UIImage imageNamed:@"bar-separator.png"];
separatorBarButton = [UIBarButtonItem barItemWithImage:separatorImage target:nil action:nil]; separatorBarButton = [UIBarButtonItem barItemWithImage:separatorImage target:nil action:nil];
@ -94,12 +88,18 @@
UIImage *settingsImage = [UIImage imageNamed:@"nav_icn_settings.png"]; UIImage *settingsImage = [UIImage imageNamed:@"nav_icn_settings.png"];
settingsBarButton = [UIBarButtonItem barItemWithImage:settingsImage target:self action:@selector(doOpenSettingsActionSheet:)]; settingsBarButton = [UIBarButtonItem barItemWithImage:settingsImage target:self action:@selector(doOpenSettingsActionSheet:)];
UIImage *markreadImage = [UIImage imageNamed:@"markread.png"]; UIImage *markreadImage = [UIImage imageNamed:@"markread.png"];
feedMarkReadButton = [UIBarButtonItem barItemWithImage:markreadImage target:self action:@selector(doOpenMarkReadActionSheet:)]; feedMarkReadButton = [UIBarButtonItem barItemWithImage:markreadImage target:self action:@selector(doOpenMarkReadActionSheet:)];
titleImageBarButton = [UIBarButtonItem alloc]; titleImageBarButton = [UIBarButtonItem alloc];
UILongPressGestureRecognizer *longpress = [[UILongPressGestureRecognizer alloc]
initWithTarget:self action:@selector(handleLongPress:)];
longpress.minimumPressDuration = 1.0;
longpress.delegate = self;
[self.storyTitlesTable addGestureRecognizer:longpress];
self.notifier = [[NBNotifier alloc] initWithTitle:@"Fetching stories..." inView:self.view]; self.notifier = [[NBNotifier alloc] initWithTitle:@"Fetching stories..." inView:self.view];
[self.view addSubview:self.notifier]; [self.view addSubview:self.notifier];
} }
@ -122,39 +122,49 @@
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
[self setUserAvatarLayout:orientation]; [self setUserAvatarLayout:orientation];
self.finishedAnimatingIn = NO; self.finishedAnimatingIn = NO;
[MBProgressHUD hideHUDForView:self.view animated:YES]; [MBProgressHUD hideHUDForView:self.view animated:NO];
// set center title
UILabel *titleLabel = (UILabel *)[appDelegate makeFeedTitle:appDelegate.activeFeed];
self.navigationItem.titleView = titleLabel;
// set right avatar title image // set right avatar title image
spacerBarButton.width = 0;
spacer2BarButton.width = 0;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
spacerBarButton.width = -6;
spacer2BarButton.width = 10;
}
if (appDelegate.isSocialView) { if (appDelegate.isSocialView) {
UIButton *titleImageButton = [appDelegate makeRightFeedTitle:appDelegate.activeFeed]; spacerBarButton.width = -6;
[titleImageButton addTarget:self action:@selector(showUserProfile) forControlEvents:UIControlEventTouchUpInside]; NSString *feedIdStr = [NSString stringWithFormat:@"%@", [appDelegate.activeFeed objectForKey:@"id"]];
titleImageBarButton.customView = titleImageButton; UIImage *titleImage = [Utilities getImage:feedIdStr isSocial:YES];
[rightToolbar setItems: [NSArray arrayWithObjects: titleImage = [Utilities roundCorneredImage:titleImage radius:6];
spacerBarButton, [((UIButton *)titleImageBarButton.customView).imageView removeFromSuperview];
feedMarkReadButton, titleImageBarButton = [UIBarButtonItem barItemWithImage:titleImage
spacer2BarButton, target:self
separatorBarButton, action:@selector(showUserProfile)];
spacer3BarButton, titleImageBarButton.customView.frame = CGRectMake(0, 0, 32, 32);
titleImageBarButton, nil]]; self.navigationItem.rightBarButtonItems = [NSArray arrayWithObjects:
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:rightToolbar]; spacerBarButton,
titleImageBarButton.enabled = YES; titleImageBarButton,
spacer2BarButton,
separatorBarButton,
feedMarkReadButton, nil];
} else { } else {
[rightToolbar setItems: [NSArray arrayWithObjects: self.navigationItem.rightBarButtonItems = [NSArray arrayWithObjects:
spacerBarButton, spacerBarButton,
feedMarkReadButton, settingsBarButton,
spacer2BarButton, spacer2BarButton,
separatorBarButton, separatorBarButton,
spacer3BarButton, feedMarkReadButton,
settingsBarButton, nil]]; nil];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:rightToolbar]; }
// set center title
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone &&
!self.navigationItem.titleView) {
self.navigationItem.titleView = [appDelegate makeFeedTitle:appDelegate.activeFeed];
} }
NSMutableArray *indexPaths = [NSMutableArray array]; NSMutableArray *indexPaths = [NSMutableArray array];
NSLog(@"appDelegate.recentlyReadStoryLocations: %d - %@", self.isOffline, appDelegate.recentlyReadStoryLocations); // NSLog(@"appDelegate.recentlyReadStoryLocations: %d - %@", self.isOffline, appDelegate.recentlyReadStoryLocations);
for (id i in appDelegate.recentlyReadStoryLocations) { for (id i in appDelegate.recentlyReadStoryLocations) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[i intValue] NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[i intValue]
inSection:0]; inSection:0];
@ -164,17 +174,15 @@
} }
} }
if ([indexPaths count] > 0 && [self.storyTitlesTable numberOfRowsInSection:0]) { if ([indexPaths count] > 0 && [self.storyTitlesTable numberOfRowsInSection:0]) {
[self.storyTitlesTable beginUpdates]; // [self.storyTitlesTable beginUpdates];
[self.storyTitlesTable reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone]; // [self.storyTitlesTable reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
[self.storyTitlesTable endUpdates]; // [self.storyTitlesTable endUpdates];
//[self.storyTitlesTable reloadData]; [self.storyTitlesTable reloadData];
} }
appDelegate.recentlyReadStoryLocations = [NSMutableArray array]; appDelegate.recentlyReadStoryLocations = [NSMutableArray array];
appDelegate.originalStoryCount = [appDelegate unreadCount]; appDelegate.originalStoryCount = [appDelegate unreadCount];
[super viewWillAppear:animated];
if ((appDelegate.isSocialRiverView || if ((appDelegate.isSocialRiverView ||
appDelegate.isSocialView || appDelegate.isSocialView ||
[appDelegate.activeFolder isEqualToString:@"saved_stories"])) { [appDelegate.activeFolder isEqualToString:@"saved_stories"])) {
@ -192,7 +200,7 @@
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
[self.storyTitlesTable reloadData]; [self.storyTitlesTable reloadData];
int location = appDelegate.locationOfActiveStory; NSInteger location = appDelegate.locationOfActiveStory;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:location inSection:0]; NSIndexPath *indexPath = [NSIndexPath indexPathForRow:location inSection:0];
if (indexPath && location >= 0) { if (indexPath && location >= 0) {
[self.storyTitlesTable selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionMiddle]; [self.storyTitlesTable selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionMiddle];
@ -216,19 +224,14 @@
[self testForTryFeed]; [self testForTryFeed];
} }
- (void)viewWillDisappear:(BOOL)animated { - (void)viewDidDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self.popoverController dismissPopoverAnimated:YES]; [self.popoverController dismissPopoverAnimated:YES];
self.popoverController = nil; self.popoverController = nil;
} }
- (void)viewDidDisappear:(BOOL)animated {
}
- (void)fadeSelectedCell { - (void)fadeSelectedCell {
// have the selected cell deselect // have the selected cell deselect
int location = appDelegate.locationOfActiveStory; NSInteger location = appDelegate.locationOfActiveStory;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:location inSection:0]; NSIndexPath *indexPath = [NSIndexPath indexPathForRow:location inSection:0];
if (indexPath) { if (indexPath) {
@ -241,12 +244,12 @@
- (void)setUserAvatarLayout:(UIInterfaceOrientation)orientation { - (void)setUserAvatarLayout:(UIInterfaceOrientation)orientation {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone && appDelegate.isSocialView) { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone && appDelegate.isSocialView) {
if (UIInterfaceOrientationIsPortrait(orientation)) { if (UIInterfaceOrientationIsPortrait(orientation)) {
UIButton *avatar = (UIButton *)titleImageBarButton.customView; NBBarButtonItem *avatar = (NBBarButtonItem *)titleImageBarButton.customView;
CGRect buttonFrame = avatar.frame; CGRect buttonFrame = avatar.frame;
buttonFrame.size = CGSizeMake(32, 32); buttonFrame.size = CGSizeMake(32, 32);
avatar.frame = buttonFrame; avatar.frame = buttonFrame;
} else { } else {
UIButton *avatar = (UIButton *)titleImageBarButton.customView; NBBarButtonItem *avatar = (NBBarButtonItem *)titleImageBarButton.customView;
CGRect buttonFrame = avatar.frame; CGRect buttonFrame = avatar.frame;
buttonFrame.size = CGSizeMake(28, 28); buttonFrame.size = CGSizeMake(28, 28);
avatar.frame = buttonFrame; avatar.frame = buttonFrame;
@ -254,12 +257,12 @@
} }
} }
#pragma mark - #pragma mark -
#pragma mark Initialization #pragma mark Initialization
- (void)resetFeedDetail { - (void)resetFeedDetail {
appDelegate.hasLoadedFeedDetail = NO; appDelegate.hasLoadedFeedDetail = NO;
self.navigationItem.titleView = nil;
self.pageFetching = NO; self.pageFetching = NO;
self.pageFinished = NO; self.pageFinished = NO;
self.isOffline = NO; self.isOffline = NO;
@ -295,7 +298,8 @@
- (void)beginOfflineTimer { - (void)beginOfflineTimer {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
if (!appDelegate.storyLocationsCount && self.feedPage == 1) { if (!appDelegate.storyLocationsCount && !self.pageFinished &&
self.feedPage == 1 && !self.isOffline) {
self.isShowingOffline = YES; self.isShowingOffline = YES;
self.isOffline = YES; self.isOffline = YES;
[self showLoadingNotifier]; [self showLoadingNotifier];
@ -324,7 +328,7 @@
self.feedPage = page; self.feedPage = page;
self.pageFetching = YES; self.pageFetching = YES;
int storyCount = appDelegate.storyCount; NSInteger storyCount = appDelegate.storyCount;
if (storyCount == 0) { if (storyCount == 0) {
[self.storyTitlesTable reloadData]; [self.storyTitlesTable reloadData];
[storyTitlesTable scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES]; [storyTitlesTable scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
@ -375,13 +379,11 @@
if (request.isCancelled) { if (request.isCancelled) {
NSLog(@"Cancelled"); NSLog(@"Cancelled");
return; return;
} else if (self.feedPage == 1) { } else {
self.isOffline = YES; self.isOffline = YES;
self.feedPage = 1;
[self loadOfflineStories]; [self loadOfflineStories];
[self showOfflineNotifier]; [self showOfflineNotifier];
} else {
[self informError:[request error]];
self.pageFinished = YES;
} }
[self.storyTitlesTable reloadData]; [self.storyTitlesTable reloadData];
}]; }];
@ -404,8 +406,8 @@
(unsigned long)NULL), ^(void) { (unsigned long)NULL), ^(void) {
[appDelegate.database inDatabase:^(FMDatabase *db) { [appDelegate.database inDatabase:^(FMDatabase *db) {
NSArray *feedIds; NSArray *feedIds;
int limit = 12; NSInteger limit = 12;
int offset = (self.feedPage - 1) * limit; NSInteger offset = (self.feedPage - 1) * limit;
if (appDelegate.isRiverView) { if (appDelegate.isRiverView) {
feedIds = appDelegate.activeFolderFeeds; feedIds = appDelegate.activeFolderFeeds;
@ -427,11 +429,11 @@
} else { } else {
readFilterSql = @""; readFilterSql = @"";
} }
NSString *sql = [NSString stringWithFormat:@"SELECT * FROM stories s %@ WHERE s.story_feed_id IN (%@) ORDER BY s.story_timestamp %@ LIMIT %d OFFSET %d", NSString *sql = [NSString stringWithFormat:@"SELECT * FROM stories s %@ WHERE s.story_feed_id IN (%@) ORDER BY s.story_timestamp %@ LIMIT %ld OFFSET %ld",
readFilterSql, readFilterSql,
[feedIds componentsJoinedByString:@","], [feedIds componentsJoinedByString:@","],
orderSql, orderSql,
limit, offset]; (long)limit, (long)offset];
FMResultSet *cursor = [db executeQuery:sql]; FMResultSet *cursor = [db executeQuery:sql];
NSMutableArray *offlineStories = [NSMutableArray array]; NSMutableArray *offlineStories = [NSMutableArray array];
@ -442,6 +444,7 @@
dataUsingEncoding:NSUTF8StringEncoding] dataUsingEncoding:NSUTF8StringEncoding]
options:nil error:nil]]; options:nil error:nil]];
} }
[cursor close];
if ([appDelegate.activeReadFilter isEqualToString:@"all"]) { if ([appDelegate.activeReadFilter isEqualToString:@"all"]) {
NSString *unreadHashSql = [NSString stringWithFormat:@"SELECT s.story_hash FROM stories s INNER JOIN unread_hashes uh ON s.story_hash = uh.story_hash WHERE s.story_feed_id IN (%@)", NSString *unreadHashSql = [NSString stringWithFormat:@"SELECT s.story_hash FROM stories s INNER JOIN unread_hashes uh ON s.story_hash = uh.story_hash WHERE s.story_feed_id IN (%@)",
@ -457,9 +460,10 @@
[unreadStoryHashes setObject:[NSNumber numberWithBool:YES] forKey:[unreadHashCursor objectForColumnName:@"story_hash"]]; [unreadStoryHashes setObject:[NSNumber numberWithBool:YES] forKey:[unreadHashCursor objectForColumnName:@"story_hash"]];
} }
appDelegate.unreadStoryHashes = unreadStoryHashes; appDelegate.unreadStoryHashes = unreadStoryHashes;
[unreadHashCursor close];
} }
dispatch_sync(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
if (!self.isOffline) { if (!self.isOffline) {
NSLog(@"Online before offline rendered. Tossing offline stories."); NSLog(@"Online before offline rendered. Tossing offline stories.");
return; return;
@ -499,7 +503,7 @@
if (!self.pageFetching && !self.pageFinished) { if (!self.pageFetching && !self.pageFinished) {
self.feedPage = page; self.feedPage = page;
self.pageFetching = YES; self.pageFetching = YES;
int storyCount = appDelegate.storyCount; NSInteger storyCount = appDelegate.storyCount;
if (storyCount == 0) { if (storyCount == 0) {
[self.storyTitlesTable reloadData]; [self.storyTitlesTable reloadData];
[storyTitlesTable scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES]; [storyTitlesTable scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
@ -566,15 +570,12 @@
if (request.isCancelled) { if (request.isCancelled) {
NSLog(@"Cancelled"); NSLog(@"Cancelled");
return; return;
} else if (self.feedPage == 1) { } else {
self.isOffline = YES; self.isOffline = YES;
self.isShowingOffline = NO; self.isShowingOffline = NO;
self.feedPage = 1;
[self loadOfflineStories]; [self loadOfflineStories];
[self showOfflineNotifier]; [self showOfflineNotifier];
} else {
[self informError:[request error]];
self.pageFinished = YES;
[self.storyTitlesTable reloadData];
} }
}]; }];
[request setCompletionBlock:^(void) { [request setCompletionBlock:^(void) {
@ -596,12 +597,11 @@
NSLog(@"Cancelled"); NSLog(@"Cancelled");
return; return;
} else if ([request responseStatusCode] >= 500) { } else if ([request responseStatusCode] >= 500) {
if (self.feedPage == 1) { self.isOffline = YES;
self.isOffline = YES; self.isShowingOffline = NO;
self.isShowingOffline = NO; self.feedPage = 1;
[self loadOfflineStories]; [self loadOfflineStories];
[self showOfflineNotifier]; [self showOfflineNotifier];
}
if ([request responseStatusCode] == 503) { if ([request responseStatusCode] == 503) {
[self informError:@"In maintenance mode"]; [self informError:@"In maintenance mode"];
self.pageFinished = YES; self.pageFinished = YES;
@ -646,7 +646,7 @@
for (id key in [newClassifiers allKeys]) { for (id key in [newClassifiers allKeys]) {
[appDelegate.activeClassifiers setObject:[newClassifiers objectForKey:key] forKey:key]; [appDelegate.activeClassifiers setObject:[newClassifiers objectForKey:key] forKey:key];
} }
} else { } else if (newClassifiers) {
[appDelegate.activeClassifiers setObject:newClassifiers forKey:feedIdStr]; [appDelegate.activeClassifiers setObject:newClassifiers forKey:feedIdStr];
} }
appDelegate.activePopularAuthors = [results objectForKey:@"feed_authors"]; appDelegate.activePopularAuthors = [results objectForKey:@"feed_authors"];
@ -774,12 +774,12 @@
if ([storyIdStr isEqualToString:appDelegate.tryFeedStoryId]) { if ([storyIdStr isEqualToString:appDelegate.tryFeedStoryId]) {
NSDictionary *feed = [appDelegate.activeFeedStories objectAtIndex:i]; NSDictionary *feed = [appDelegate.activeFeedStories objectAtIndex:i];
int score = [NewsBlurAppDelegate computeStoryScore:[feed objectForKey:@"intelligence"]]; NSInteger score = [NewsBlurAppDelegate computeStoryScore:[feed objectForKey:@"intelligence"]];
if (score < appDelegate.selectedIntelligence) { if (score < appDelegate.selectedIntelligence) {
[self changeIntelligence:score]; [self changeIntelligence:score];
} }
int locationOfStoryId = [appDelegate locationOfStoryId:storyIdStr]; NSInteger locationOfStoryId = [appDelegate locationOfStoryId:storyIdStr];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:locationOfStoryId inSection:0]; NSIndexPath *indexPath = [NSIndexPath indexPathForRow:locationOfStoryId inSection:0];
[self.storyTitlesTable selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionBottom]; [self.storyTitlesTable selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionBottom];
@ -811,7 +811,7 @@
} }
- (UITableViewCell *)makeLoadingCell { - (UITableViewCell *)makeLoadingCell {
int height = 40; NSInteger height = 40;
UITableViewCell *cell = [[UITableViewCell alloc] UITableViewCell *cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleSubtitle initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:@"NoReuse"]; reuseIdentifier:@"NoReuse"];
@ -831,6 +831,7 @@
fleuron.frame = CGRectMake(0, 0, self.view.frame.size.width, height); fleuron.frame = CGRectMake(0, 0, self.view.frame.size.width, height);
fleuron.contentMode = UIViewContentModeCenter; fleuron.contentMode = UIViewContentModeCenter;
[cell.contentView addSubview:fleuron]; [cell.contentView addSubview:fleuron];
cell.backgroundColor = [UIColor clearColor];
return cell; return cell;
} else {//if ([appDelegate.storyLocationsCount]) { } else {//if ([appDelegate.storyLocationsCount]) {
NBLoadingCell *loadingCell = [[NBLoadingCell alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, height)]; NBLoadingCell *loadingCell = [[NBLoadingCell alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, height)];
@ -844,7 +845,7 @@
#pragma mark Table View - Feed List #pragma mark Table View - Feed List
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
int storyCount = appDelegate.storyLocationsCount; NSInteger storyCount = appDelegate.storyLocationsCount;
// The +1 is for the finished/loading bar. // The +1 is for the finished/loading bar.
return storyCount + 1; return storyCount + 1;
@ -856,23 +857,23 @@
NSString *cellIdentifier; NSString *cellIdentifier;
NSDictionary *feed ; NSDictionary *feed ;
if (indexPath.row >= appDelegate.storyLocationsCount) {
return [self makeLoadingCell];
}
if (appDelegate.isRiverView || appDelegate.isSocialView) { if (appDelegate.isRiverView || appDelegate.isSocialView) {
cellIdentifier = @"FeedRiverDetailCellIdentifier"; cellIdentifier = @"FeedRiverDetailCellIdentifier";
} else { } else {
cellIdentifier = @"FeedDetailCellIdentifier"; cellIdentifier = @"FeedDetailCellIdentifier";
} }
FeedDetailTableCell *cell = (FeedDetailTableCell *)[tableView FeedDetailTableCell *cell = (FeedDetailTableCell *)[tableView
dequeueReusableCellWithIdentifier:cellIdentifier]; dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) { if (cell == nil) {
cell = [[FeedDetailTableCell alloc] initWithStyle:UITableViewCellStyleDefault cell = [[FeedDetailTableCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:nil]; reuseIdentifier:nil];
} }
if (indexPath.row >= appDelegate.storyLocationsCount) {
return [self makeLoadingCell];
}
NSDictionary *story = [self getStoryAtRow:indexPath.row]; NSDictionary *story = [self getStoryAtRow:indexPath.row];
id feedId = [story objectForKey:@"story_feed_id"]; id feedId = [story objectForKey:@"story_feed_id"];
@ -893,10 +894,11 @@
NSString *title = [story objectForKey:@"story_title"]; NSString *title = [story objectForKey:@"story_title"];
cell.storyTitle = [title stringByDecodingHTMLEntities]; cell.storyTitle = [title stringByDecodingHTMLEntities];
cell.storyDate = [story objectForKey:@"short_parsed_date"]; cell.storyDate = [story objectForKey:@"short_parsed_date"];
cell.isStarred = [story objectForKey:@"starred"]; cell.storyTimestamp = [[story objectForKey:@"story_timestamp"] integerValue];
cell.isShared = [story objectForKey:@"shared"]; cell.isStarred = [[story objectForKey:@"starred"] boolValue];
cell.isShared = [[story objectForKey:@"shared"] boolValue];
if ([[story objectForKey:@"story_authors"] class] != [NSNull class]) { if ([[story objectForKey:@"story_authors"] class] != [NSNull class]) {
cell.storyAuthor = [[story objectForKey:@"story_authors"] uppercaseString]; cell.storyAuthor = [[story objectForKey:@"story_authors"] uppercaseString];
@ -930,19 +932,15 @@
// undread indicator // undread indicator
int score = [NewsBlurAppDelegate computeStoryScore:[story objectForKey:@"intelligence"]]; NSInteger score = [NewsBlurAppDelegate computeStoryScore:[story objectForKey:@"intelligence"]];
cell.storyScore = score; cell.storyScore = score;
if (!appDelegate.hasLoadedFeedDetail) { cell.isRead = ![appDelegate isStoryUnread:story];
cell.isRead = ([appDelegate.activeReadFilter isEqualToString:@"all"] && // if (!appDelegate.hasLoadedFeedDetail) {
![[appDelegate.unreadStoryHashes objectForKey:[story objectForKey:@"story_hash"]] boolValue]) ||
[[appDelegate.recentlyReadStories objectForKey:[story objectForKey:@"story_hash"]] boolValue];
// NSLog(@"Offline: %d (%d/%d) - %@ - %@", cell.isRead, ![[appDelegate.unreadStoryHashes objectForKey:[story objectForKey:@"story_hash"]] boolValue], [[appDelegate.recentlyReadStories objectForKey:[story objectForKey:@"story_hash"]] boolValue], [story objectForKey:@"story_title"], [story objectForKey:@"story_hash"]); // NSLog(@"Offline: %d (%d/%d) - %@ - %@", cell.isRead, ![[appDelegate.unreadStoryHashes objectForKey:[story objectForKey:@"story_hash"]] boolValue], [[appDelegate.recentlyReadStories objectForKey:[story objectForKey:@"story_hash"]] boolValue], [story objectForKey:@"story_title"], [story objectForKey:@"story_hash"]);
} else { // } else {
cell.isRead = [[story objectForKey:@"read_status"] intValue] == 1 ||
[[appDelegate.recentlyReadStories objectForKey:[story objectForKey:@"story_hash"]] boolValue];
// NSLog(@"Online: %d (%d/%d) - %@ - %@", cell.isRead, [[story objectForKey:@"read_status"] intValue] == 1, [[appDelegate.recentlyReadStories objectForKey:[story objectForKey:@"story_hash"]] boolValue], [story objectForKey:@"story_title"], [story objectForKey:@"story_hash"]); // NSLog(@"Online: %d (%d/%d) - %@ - %@", cell.isRead, [[story objectForKey:@"read_status"] intValue] == 1, [[appDelegate.recentlyReadStories objectForKey:[story objectForKey:@"story_hash"]] boolValue], [story objectForKey:@"story_title"], [story objectForKey:@"story_hash"]);
} // }
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad
@ -955,36 +953,40 @@
cell.isRiverOrSocial = YES; cell.isRiverOrSocial = YES;
} }
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
int rowIndex = [appDelegate locationOfActiveStory]; NSInteger rowIndex = [appDelegate locationOfActiveStory];
if (rowIndex == indexPath.row) { if (rowIndex == indexPath.row) {
[self.storyTitlesTable selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone]; [self.storyTitlesTable selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
} }
} }
[cell setupGestures];
return cell; return cell;
} }
- (void)loadStory:(FeedDetailTableCell *)cell atRow:(int)row { - (void)loadStory:(FeedDetailTableCell *)cell atRow:(NSInteger)row {
cell.isRead = YES; NSInteger storyIndex = [appDelegate indexFromLocation:row];
[cell setNeedsLayout];
int storyIndex = [appDelegate indexFromLocation:row];
appDelegate.activeStory = [[appDelegate activeFeedStories] objectAtIndex:storyIndex]; appDelegate.activeStory = [[appDelegate activeFeedStories] objectAtIndex:storyIndex];
if ([appDelegate isStoryUnread:appDelegate.activeStory]) {
[self markStoryAsRead:appDelegate.activeStory];
}
[appDelegate loadStoryDetailView]; [appDelegate loadStoryDetailView];
[self redrawUnreadStory];
} }
- (void)redrawUnreadStory { - (void)redrawUnreadStory {
int rowIndex = [appDelegate locationOfActiveStory]; NSInteger rowIndex = [appDelegate locationOfActiveStory];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:rowIndex inSection:0]; NSIndexPath *indexPath = [NSIndexPath indexPathForRow:rowIndex inSection:0];
FeedDetailTableCell *cell = (FeedDetailTableCell*) [self.storyTitlesTable cellForRowAtIndexPath:indexPath]; FeedDetailTableCell *cell = (FeedDetailTableCell*) [self.storyTitlesTable cellForRowAtIndexPath:indexPath];
cell.isRead = [[appDelegate.activeStory objectForKey:@"read_status"] boolValue]; cell.isRead = ![appDelegate isStoryUnread:appDelegate.activeStory];
cell.isShared = [[appDelegate.activeStory objectForKey:@"shared"] boolValue]; cell.isShared = [[appDelegate.activeStory objectForKey:@"shared"] boolValue];
cell.isStarred = [[appDelegate.activeStory objectForKey:@"starred"] boolValue]; cell.isStarred = [[appDelegate.activeStory objectForKey:@"starred"] boolValue];
[cell setNeedsDisplay]; [cell setNeedsDisplay];
} }
- (void)changeActiveStoryTitleCellLayout { - (void)changeActiveStoryTitleCellLayout {
int rowIndex = [appDelegate locationOfActiveStory]; NSInteger rowIndex = [appDelegate locationOfActiveStory];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:rowIndex inSection:0]; NSIndexPath *indexPath = [NSIndexPath indexPathForRow:rowIndex inSection:0];
FeedDetailTableCell *cell = (FeedDetailTableCell*) [self.storyTitlesTable cellForRowAtIndexPath:indexPath]; FeedDetailTableCell *cell = (FeedDetailTableCell*) [self.storyTitlesTable cellForRowAtIndexPath:indexPath];
cell.isRead = YES; cell.isRead = YES;
@ -1012,12 +1014,12 @@
} }
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
int storyCount = appDelegate.storyLocationsCount; NSInteger storyCount = appDelegate.storyLocationsCount;
if (storyCount && indexPath.row == storyCount) { if (storyCount && indexPath.row == storyCount) {
return 40; return 40;
} else if (appDelegate.isRiverView || appDelegate.isSocialView || appDelegate.isSocialRiverView) { } else if (appDelegate.isRiverView || appDelegate.isSocialView || appDelegate.isSocialRiverView) {
int height = kTableViewRiverRowHeight; NSInteger height = kTableViewRiverRowHeight;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad
&& !appDelegate.masterContainerViewController.storyTitlesOnLeft && !appDelegate.masterContainerViewController.storyTitlesOnLeft
&& UIInterfaceOrientationIsPortrait(orientation)) { && UIInterfaceOrientationIsPortrait(orientation)) {
@ -1025,7 +1027,7 @@
} }
return height; return height;
} else { } else {
int height = kTableViewRowHeight; NSInteger height = kTableViewRowHeight;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad
&& !appDelegate.masterContainerViewController.storyTitlesOnLeft && !appDelegate.masterContainerViewController.storyTitlesOnLeft
&& UIInterfaceOrientationIsPortrait(orientation)) { && UIInterfaceOrientationIsPortrait(orientation)) {
@ -1034,7 +1036,10 @@
return height; return height;
} }
} }
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
// This will create a "invisible" footer
return 0.01f;
}
- (void)scrollViewDidScroll: (UIScrollView *)scroll { - (void)scrollViewDidScroll: (UIScrollView *)scroll {
[self checkScroll]; [self checkScroll];
} }
@ -1073,16 +1078,80 @@
} }
- (NSDictionary *)getStoryAtRow:(NSInteger)indexPathRow { - (NSDictionary *)getStoryAtRow:(NSInteger)indexPathRow {
int row = [[[appDelegate activeFeedStoryLocations] objectAtIndex:indexPathRow] intValue]; NSInteger row = [[[appDelegate activeFeedStoryLocations] objectAtIndex:indexPathRow] intValue];
return [appDelegate.activeFeedStories objectAtIndex:row]; return [appDelegate.activeFeedStories objectAtIndex:row];
} }
#pragma mark - MCSwipeTableViewCellDelegate
// When the user starts swiping the cell this method is called
- (void)swipeTableViewCellDidStartSwiping:(MCSwipeTableViewCell *)cell {
// NSLog(@"Did start swiping the cell!");
}
// When the user is dragging, this method is called and return the dragged percentage from the border
- (void)swipeTableViewCell:(MCSwipeTableViewCell *)cell didSwipWithPercentage:(CGFloat)percentage {
// NSLog(@"Did swipe with percentage : %f", percentage);
}
- (void)swipeTableViewCell:(MCSwipeTableViewCell *)cell didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state mode:(MCSwipeTableViewCellMode)mode {
NSIndexPath *indexPath = [self.storyTitlesTable indexPathForCell:cell];
if (!indexPath) {
// This can happen if the user swipes on a cell that is being refreshed.
return;
}
NSInteger storyIndex = [appDelegate indexFromLocation:indexPath.row];
NSDictionary *story = [[appDelegate activeFeedStories] objectAtIndex:storyIndex];
if (state == MCSwipeTableViewCellState1) {
// Saved
if ([[story objectForKey:@"starred"] boolValue]) {
[self markStoryAsUnsaved:story];
} else {
[self markStoryAsSaved:story];
}
[self.storyTitlesTable reloadRowsAtIndexPaths:@[indexPath]
withRowAnimation:UITableViewRowAnimationFade];
} else if (state == MCSwipeTableViewCellState3) {
// Read
if ([[story objectForKey:@"read_status"] boolValue]) {
[self markStoryAsUnread:story];
} else {
[self markStoryAsRead:story];
}
[self.storyTitlesTable reloadRowsAtIndexPaths:@[indexPath]
withRowAnimation:UITableViewRowAnimationFade];
}
}
#pragma mark - #pragma mark -
#pragma mark Feed Actions #pragma mark Feed Actions
- (void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer {
CGPoint p = [gestureRecognizer locationInView:self.storyTitlesTable];
NSIndexPath *indexPath = [self.storyTitlesTable indexPathForRowAtPoint:p];
FeedDetailTableCell *cell = (FeedDetailTableCell *)[self.storyTitlesTable cellForRowAtIndexPath:indexPath];
if (gestureRecognizer.state != UIGestureRecognizerStateBegan) return;
if (indexPath == nil) return;
NSDictionary *story = [self getStoryAtRow:indexPath.row];
appDelegate.activeStory = story;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[appDelegate.masterContainerViewController showSendToPopover:cell];
} else {
[self presentViewController:[UIActivitiesControl activityViewControllerForView:self]
animated:YES
completion:nil];
}
}
- (void)markFeedsReadWithAllStories:(BOOL)includeHidden { - (void)markFeedsReadWithAllStories:(BOOL)includeHidden {
if (!self.isOffline && appDelegate.isRiverView && includeHidden && if (appDelegate.isRiverView && includeHidden &&
[appDelegate.activeFolder isEqualToString:@"everything"]) { [appDelegate.activeFolder isEqualToString:@"everything"]) {
// Mark folder as read // Mark folder as read
NSString *urlString = [NSString stringWithFormat:@"%@/reader/mark_all_as_read", NSString *urlString = [NSString stringWithFormat:@"%@/reader/mark_all_as_read",
@ -1093,7 +1162,7 @@
[request startAsynchronous]; [request startAsynchronous];
[appDelegate markActiveFolderAllRead]; [appDelegate markActiveFolderAllRead];
} else if (!self.isOffline && appDelegate.isRiverView && includeHidden) { } else if (appDelegate.isRiverView && includeHidden) {
// Mark folder as read // Mark folder as read
NSString *urlString = [NSString stringWithFormat:@"%@/reader/mark_feed_as_read", NSString *urlString = [NSString stringWithFormat:@"%@/reader/mark_feed_as_read",
NEWSBLUR_URL]; NEWSBLUR_URL];
@ -1102,11 +1171,14 @@
for (id feed_id in [appDelegate.dictFolders objectForKey:appDelegate.activeFolder]) { for (id feed_id in [appDelegate.dictFolders objectForKey:appDelegate.activeFolder]) {
[request addPostValue:feed_id forKey:@"feed_id"]; [request addPostValue:feed_id forKey:@"feed_id"];
} }
[request setDelegate:nil]; [request setUserInfo:@{@"feeds": appDelegate.activeFolderFeeds}];
[request setDelegate:self];
[request setDidFinishSelector:@selector(finishMarkAllAsRead:)];
[request setDidFailSelector:@selector(requestFailed:)];
[request startAsynchronous]; [request startAsynchronous];
[appDelegate markActiveFolderAllRead]; [appDelegate markActiveFolderAllRead];
} else if (!self.isOffline && !appDelegate.isRiverView && includeHidden) { } else if (!appDelegate.isRiverView && includeHidden) {
// Mark feed as read // Mark feed as read
NSString *urlString = [NSString stringWithFormat:@"%@/reader/mark_feed_as_read", NSString *urlString = [NSString stringWithFormat:@"%@/reader/mark_feed_as_read",
NEWSBLUR_URL]; NEWSBLUR_URL];
@ -1115,6 +1187,7 @@
[request setPostValue:[appDelegate.activeFeed objectForKey:@"id"] forKey:@"feed_id"]; [request setPostValue:[appDelegate.activeFeed objectForKey:@"id"] forKey:@"feed_id"];
[request setDidFinishSelector:@selector(finishMarkAllAsRead:)]; [request setDidFinishSelector:@selector(finishMarkAllAsRead:)];
[request setDidFailSelector:@selector(requestFailed:)]; [request setDidFailSelector:@selector(requestFailed:)];
[request setUserInfo:@{@"feeds": @[[appDelegate.activeFeed objectForKey:@"id"]]}];
[request setDelegate:self]; [request setDelegate:self];
[request startAsynchronous]; [request startAsynchronous];
[appDelegate markFeedAllRead:[appDelegate.activeFeed objectForKey:@"id"]]; [appDelegate markFeedAllRead:[appDelegate.activeFeed objectForKey:@"id"]];
@ -1127,49 +1200,12 @@
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url]; ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:[feedsStories JSONRepresentation] forKey:@"feeds_stories"]; [request setPostValue:[feedsStories JSONRepresentation] forKey:@"feeds_stories"];
[request setDelegate:self]; [request setDelegate:self];
[request setUserInfo:feedsStories]; [request setUserInfo:@{@"stories": feedsStories}];
[request setDidFinishSelector:@selector(finishMarkAllAsRead:)]; [request setDidFinishSelector:@selector(finishMarkAllAsRead:)];
[request setDidFailSelector:@selector(requestFailedMarkStoryRead:)]; [request setDidFailSelector:@selector(requestFailedMarkStoryRead:)];
[request startAsynchronous]; [request startAsynchronous];
} else {
// Must be offline and marking all as read, so load all stories.
NSMutableDictionary *feedsStories = [NSMutableDictionary dictionary];
[appDelegate.database inDatabase:^(FMDatabase *db) {
NSArray *feedIds;
if (appDelegate.isRiverView) {
feedIds = appDelegate.activeFolderFeeds;
} else if (appDelegate.activeFeed) {
feedIds = @[[appDelegate.activeFeed objectForKey:@"id"]];
} else {
return;
}
NSString *sql = [NSString stringWithFormat:@"SELECT u.story_feed_id, u.story_hash "
"FROM unread_hashes u WHERE u.story_feed_id IN (%@)",
[feedIds componentsJoinedByString:@","]];
FMResultSet *cursor = [db executeQuery:sql];
while ([cursor next]) {
NSDictionary *story = [cursor resultDictionary];
NSString *feedIdStr = [story objectForKey:@"story_feed_id"];
NSString *storyHash = [story objectForKey:@"story_hash"];
if (![feedsStories objectForKey:feedIdStr]) {
[feedsStories setObject:[NSMutableArray array] forKey:feedIdStr];
}
NSMutableArray *stories = [feedsStories objectForKey:feedIdStr];
[stories addObject:storyHash];
}
}];
for (NSString *feedId in [feedsStories allKeys]) {
[appDelegate markFeedAllRead:feedId];
}
[appDelegate queueReadStories:feedsStories];
} }
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[appDelegate.navigationController popToRootViewControllerAnimated:YES]; [appDelegate.navigationController popToRootViewControllerAnimated:YES];
[appDelegate.masterContainerViewController transitionFromFeedDetail]; [appDelegate.masterContainerViewController transitionFromFeedDetail];
@ -1183,23 +1219,20 @@
- (void)requestFailedMarkStoryRead:(ASIFormDataRequest *)request { - (void)requestFailedMarkStoryRead:(ASIFormDataRequest *)request {
// [self informError:@"Failed to mark story as read"]; // [self informError:@"Failed to mark story as read"];
NSDictionary *feedsStories = request.userInfo; [appDelegate markStoriesRead:[request.userInfo objectForKey:@"stories"]
[appDelegate queueReadStories:feedsStories]; inFeeds:[request.userInfo objectForKey:@"feeds"]
cutoffTimestamp:nil];
} }
- (void)finishMarkAllAsRead:(ASIFormDataRequest *)request { - (void)finishMarkAllAsRead:(ASIFormDataRequest *)request {
if (request.responseStatusCode != 200) { if (request.responseStatusCode != 200) {
[self requestFailedMarkStoryRead:request]; [self requestFailedMarkStoryRead:request];
return;
} }
// NSString *responseString = [request responseString];
// NSData *responseData = [responseString dataUsingEncoding:NSUTF8StringEncoding];
// NSError *error;
// NSDictionary *results = [NSJSONSerialization
// JSONObjectWithData:responseData
// options:kNilOptions
// error:&error];
if ([request.userInfo objectForKey:@"feeds"]) {
[appDelegate markFeedReadInCache:@[[request.userInfo objectForKey:@"feeds"]]];
}
} }
- (IBAction)doOpenMarkReadActionSheet:(id)sender { - (IBAction)doOpenMarkReadActionSheet:(id)sender {
@ -1228,8 +1261,8 @@
self.actionSheet_ = options; self.actionSheet_ = options;
[appDelegate calculateStoryLocations]; [appDelegate calculateStoryLocations];
int visibleUnreadCount = appDelegate.visibleUnreadCount; NSInteger visibleUnreadCount = appDelegate.visibleUnreadCount;
int totalUnreadCount = [appDelegate unreadCount]; NSInteger totalUnreadCount = [appDelegate unreadCount];
NSArray *buttonTitles = nil; NSArray *buttonTitles = nil;
BOOL showVisible = YES; BOOL showVisible = YES;
BOOL showEntire = YES; BOOL showEntire = YES;
@ -1243,8 +1276,8 @@
@"this site"]; @"this site"];
NSString *visibleText = [NSString stringWithFormat:@"Mark %@ read", NSString *visibleText = [NSString stringWithFormat:@"Mark %@ read",
visibleUnreadCount == 1 ? @"this story as" : visibleUnreadCount == 1 ? @"this story as" :
[NSString stringWithFormat:@"these %d stories", [NSString stringWithFormat:@"these %ld stories",
visibleUnreadCount]]; (long)visibleUnreadCount]];
if (showVisible && showEntire) { if (showVisible && showEntire) {
buttonTitles = [NSArray arrayWithObjects:visibleText, entireText, nil]; buttonTitles = [NSArray arrayWithObjects:visibleText, entireText, nil];
options.destructiveButtonIndex = 1; options.destructiveButtonIndex = 1;
@ -1272,8 +1305,8 @@
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
// NSLog(@"Action option #%d on %d", buttonIndex, actionSheet.tag); // NSLog(@"Action option #%d on %d", buttonIndex, actionSheet.tag);
if (actionSheet.tag == 1) { if (actionSheet.tag == 1) {
int visibleUnreadCount = appDelegate.visibleUnreadCount; NSInteger visibleUnreadCount = appDelegate.visibleUnreadCount;
int totalUnreadCount = [appDelegate unreadCount]; NSInteger totalUnreadCount = [appDelegate unreadCount];
BOOL showVisible = YES; BOOL showVisible = YES;
BOOL showEntire = YES; BOOL showEntire = YES;
// if ([appDelegate.activeFolder isEqualToString:@"everything"]) showEntire = NO; // if ([appDelegate.activeFolder isEqualToString:@"everything"]) showEntire = NO;
@ -1303,7 +1336,7 @@
} else if (buttonIndex == 2) { } else if (buttonIndex == 2) {
[self instafetchFeed]; [self instafetchFeed];
} }
} }
} }
- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex { - (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
@ -1328,7 +1361,7 @@
if ([self.popoverController respondsToSelector:@selector(setContainerViewProperties:)]) { if ([self.popoverController respondsToSelector:@selector(setContainerViewProperties:)]) {
[self.popoverController setContainerViewProperties:[self improvedContainerViewProperties]]; [self.popoverController setContainerViewProperties:[self improvedContainerViewProperties]];
} }
int menuCount = [appDelegate.feedDetailMenuViewController.menuOptions count] + 2; NSInteger menuCount = [appDelegate.feedDetailMenuViewController.menuOptions count] + 2;
[self.popoverController setPopoverContentSize:CGSizeMake(260, 38 * menuCount)]; [self.popoverController setPopoverContentSize:CGSizeMake(260, 38 * menuCount)];
[self.popoverController presentPopoverFromBarButtonItem:self.settingsBarButton [self.popoverController presentPopoverFromBarButtonItem:self.settingsBarButton
permittedArrowDirections:UIPopoverArrowDirectionUp permittedArrowDirections:UIPopoverArrowDirectionUp
@ -1429,11 +1462,11 @@
- (void)showUserProfile { - (void)showUserProfile {
appDelegate.activeUserProfileId = [NSString stringWithFormat:@"%@", [appDelegate.activeFeed objectForKey:@"user_id"]]; appDelegate.activeUserProfileId = [NSString stringWithFormat:@"%@", [appDelegate.activeFeed objectForKey:@"user_id"]];
appDelegate.activeUserProfileName = [NSString stringWithFormat:@"%@", [appDelegate.activeFeed objectForKey:@"username"]]; appDelegate.activeUserProfileName = [NSString stringWithFormat:@"%@", [appDelegate.activeFeed objectForKey:@"username"]];
[appDelegate showUserProfileModal:self.navigationItem.rightBarButtonItem]; [appDelegate showUserProfileModal:titleImageBarButton];
} }
- (void)changeActiveFeedDetailRow { - (void)changeActiveFeedDetailRow {
int rowIndex = [appDelegate locationOfActiveStory]; NSInteger rowIndex = [appDelegate locationOfActiveStory];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:rowIndex inSection:0]; NSIndexPath *indexPath = [NSIndexPath indexPathForRow:rowIndex inSection:0];
NSIndexPath *offsetIndexPath = [NSIndexPath indexPathForRow:rowIndex - 1 inSection:0]; NSIndexPath *offsetIndexPath = [NSIndexPath indexPathForRow:rowIndex - 1 inSection:0];
@ -1455,6 +1488,169 @@
} }
} }
#pragma mark -
#pragma mark Story Actions - read
- (void)markStoryAsRead:(NSDictionary *)story {
NSString *urlString = [NSString stringWithFormat:@"%@/reader/mark_story_hashes_as_read",
NEWSBLUR_URL];
NSURL *url = [NSURL URLWithString:urlString];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:[story objectForKey:@"story_hash"]
forKey:@"story_hash"];
[request setDidFinishSelector:@selector(finishMarkAsRead:)];
[request setDidFailSelector:@selector(failedMarkAsRead:)];
[request setDelegate:self];
[request setUserInfo:story];
[request startAsynchronous];
if ([appDelegate.dictFeeds objectForKey:[NSString stringWithFormat:@"%@", [story objectForKey:@"story_feed_id"]]]) {
[appDelegate markStoryRead:[story objectForKey:@"story_hash"]
feedId:[story objectForKey:@"story_feed_id"]];
}
}
- (void)finishMarkAsRead:(ASIFormDataRequest *)request {
if ([request responseStatusCode] != 200) {
return [self failedMarkAsRead:request];
}
[appDelegate.storyPageControl refreshHeaders];
}
- (void)failedMarkAsRead:(ASIFormDataRequest *)request {
NSString *storyFeedId = [request.userInfo objectForKey:@"story_feed_id"];
NSString *storyHash = [request.userInfo objectForKey:@"story_hash"];
[appDelegate queueReadStories:@{storyFeedId: @[storyHash]}];
}
- (void)markStoryAsUnread:(NSDictionary *)story {
NSString *urlString = [NSString stringWithFormat:@"%@/reader/mark_story_as_unread",
NEWSBLUR_URL];
NSURL *url = [NSURL URLWithString:urlString];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:[story objectForKey:@"story_hash"]
forKey:@"story_id"];
[request setPostValue:[story objectForKey:@"story_feed_id"]
forKey:@"feed_id"];
[request setDidFinishSelector:@selector(finishMarkAsUnread:)];
[request setDidFailSelector:@selector(failedMarkAsUnread:)];
[request setDelegate:self];
[request setUserInfo:story];
[request startAsynchronous];
[appDelegate markStoryUnread:[story objectForKey:@"story_hash"]
feedId:[story objectForKey:@"story_feed_id"]];
}
- (void)finishMarkAsUnread:(ASIFormDataRequest *)request {
NSString *responseString = [request responseString];
NSData *responseData = [responseString dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
NSDictionary *results = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error];
if ([request responseStatusCode] != 200 || [[results objectForKey:@"code"] integerValue] < 0) {
return [self failedMarkAsUnread:request];
}
appDelegate.storyPageControl.currentPage.isRecentlyUnread = YES;
[appDelegate.storyPageControl refreshHeaders];
}
- (void)failedMarkAsUnread:(ASIFormDataRequest *)request {
NSString *storyFeedId = [request.userInfo objectForKey:@"story_feed_id"];
NSString *storyHash = [request.userInfo objectForKey:@"story_hash"];
BOOL dequeued = [appDelegate dequeueReadStoryHash:storyHash inFeed:storyFeedId];
if (!dequeued) {
[self informError:@"Failed to unread story"];
[appDelegate markStoryRead:storyHash feedId:storyFeedId];
[self.storyTitlesTable reloadData];
} else {
[appDelegate.unreadStoryHashes setObject:[NSNumber numberWithBool:YES] forKey:storyHash];
[self.storyTitlesTable reloadData];
}
}
#pragma mark -
#pragma mark Story Actions - save
- (void)markStoryAsSaved:(NSDictionary *)story {
NSString *urlString = [NSString stringWithFormat:@"%@/reader/mark_story_as_starred",
NEWSBLUR_URL];
NSURL *url = [NSURL URLWithString:urlString];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:[story objectForKey:@"story_hash"]
forKey:@"story_id"];
[request setPostValue:[story objectForKey:@"story_feed_id"]
forKey:@"feed_id"];
[request setDidFinishSelector:@selector(finishMarkAsSaved:)];
[request setDidFailSelector:@selector(failedMarkAsSaved:)];
[request setDelegate:self];
[request setUserInfo:story];
[request startAsynchronous];
[appDelegate markStory:story asSaved:YES];
}
- (void)finishMarkAsSaved:(ASIFormDataRequest *)request {
if ([request responseStatusCode] != 200) {
return [self failedMarkAsSaved:request];
}
[appDelegate.storyPageControl refreshHeaders];
}
- (void)failedMarkAsSaved:(ASIFormDataRequest *)request {
[self informError:@"Failed to save story"];
[appDelegate markStory:request.userInfo asSaved:NO];
[self.storyTitlesTable reloadData];
}
- (void)markStoryAsUnsaved:(NSDictionary *)story {
NSString *urlString = [NSString stringWithFormat:@"%@/reader/mark_story_as_unstarred",
NEWSBLUR_URL];
NSURL *url = [NSURL URLWithString:urlString];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:[story objectForKey:@"story_hash"]
forKey:@"story_id"];
[request setPostValue:[story objectForKey:@"story_feed_id"]
forKey:@"feed_id"];
[request setDidFinishSelector:@selector(finishMarkAsUnsaved:)];
[request setDidFailSelector:@selector(failedMarkAsUnsaved:)];
[request setDelegate:self];
[request setUserInfo:story];
[request startAsynchronous];
[appDelegate markStory:story asSaved:NO];
}
- (void)finishMarkAsUnsaved:(ASIFormDataRequest *)request {
if ([request responseStatusCode] != 200) {
return [self failedMarkAsUnsaved:request];
}
[appDelegate.storyPageControl refreshHeaders];
}
- (void)failedMarkAsUnsaved:(ASIFormDataRequest *)request {
[self informError:@"Failed to unsave story"];
[appDelegate markStory:request.userInfo asSaved:YES];
[self.storyTitlesTable reloadData];
}
#pragma mark - #pragma mark -
#pragma mark instafetchFeed #pragma mark instafetchFeed

View file

@ -9,11 +9,9 @@
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import "NewsBlurAppDelegate.h" #import "NewsBlurAppDelegate.h"
#import "UnreadCountView.h" #import "UnreadCountView.h"
#import "ABTableViewCell.h" #import "NBSwipeableCell.h"
@class NewsBlurAppDelegate; @interface FeedTableCell : NBSwipeableCell {
@interface FeedTableCell : ABTableViewCell {
NewsBlurAppDelegate *appDelegate; NewsBlurAppDelegate *appDelegate;
NSString *feedTitle; NSString *feedTitle;
@ -23,6 +21,8 @@
int _negativeCount; int _negativeCount;
NSString *_negativeCountStr; NSString *_negativeCountStr;
BOOL isSocial; BOOL isSocial;
UIView *cellContent;
UnreadCountView *unreadCount;
} }
@property (nonatomic) NewsBlurAppDelegate *appDelegate; @property (nonatomic) NewsBlurAppDelegate *appDelegate;
@ -33,5 +33,17 @@
@property (assign, nonatomic) int negativeCount; @property (assign, nonatomic) int negativeCount;
@property (assign, nonatomic) BOOL isSocial; @property (assign, nonatomic) BOOL isSocial;
@property (nonatomic) NSString *negativeCountStr; @property (nonatomic) NSString *negativeCountStr;
@property (nonatomic) UnreadCountView *unreadCount;
- (void)setupGestures;
- (void)redrawUnreadCounts;
@end
@interface FeedTableCellView : UIView
@property (nonatomic, weak) FeedTableCell *cell;
- (void)redrawUnreadCounts;
@end @end

View file

@ -23,36 +23,50 @@ static UIFont *textFont = nil;
@synthesize negativeCount = _negativeCount; @synthesize negativeCount = _negativeCount;
@synthesize negativeCountStr; @synthesize negativeCountStr;
@synthesize isSocial; @synthesize isSocial;
@synthesize unreadCount;
+ (void) initialize{ + (void) initialize{
if (self == [FeedTableCell class]) { if (self == [FeedTableCell class]) {
textFont = [UIFont boldSystemFontOfSize:18]; textFont = [UIFont boldSystemFontOfSize:18];
// UIColor *psGrad = UIColorFromRGB(0x559F4D);
// UIColor *ntGrad = UIColorFromRGB(0xE4AB00);
// UIColor *ngGrad = UIColorFromRGB(0x9B181B);
// const CGFloat* psTop = CGColorGetComponents(ps.CGColor);
// const CGFloat* psBot = CGColorGetComponents(psGrad.CGColor);
// CGFloat psGradient[] = {
// psTop[0], psTop[1], psTop[2], psTop[3],
// psBot[0], psBot[1], psBot[2], psBot[3]
// };
// psColors = psGradient;
} }
} }
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
appDelegate = [NewsBlurAppDelegate sharedAppDelegate];
unreadCount = [UnreadCountView alloc];
unreadCount.appDelegate = self.appDelegate;
self.unreadCount = unreadCount;
cellContent = [[FeedTableCellView alloc] initWithFrame:self.frame];
cellContent.opaque = YES;
[self.contentView addSubview:cellContent];
}
return self;
}
- (void)drawRect:(CGRect)rect {
((FeedTableCellView *)cellContent).cell = self;
cellContent.frame = rect;
[cellContent setNeedsDisplay];
[self setupGestures];
}
- (void) setPositiveCount:(int)ps { - (void) setPositiveCount:(int)ps {
if (ps == _positiveCount) return; if (ps == _positiveCount) return;
_positiveCount = ps; _positiveCount = ps;
[self setNeedsDisplay]; // [cellContent setNeedsDisplay];
} }
- (void) setNeutralCount:(int)nt { - (void) setNeutralCount:(int)nt {
if (nt == _neutralCount) return; if (nt == _neutralCount) return;
_neutralCount = nt; _neutralCount = nt;
[self setNeedsDisplay]; // [cellContent setNeedsDisplay];
} }
- (void) setNegativeCount:(int)ng { - (void) setNegativeCount:(int)ng {
@ -60,97 +74,124 @@ static UIFont *textFont = nil;
_negativeCount = ng; _negativeCount = ng;
_negativeCountStr = [NSString stringWithFormat:@"%d", ng]; _negativeCountStr = [NSString stringWithFormat:@"%d", ng];
[self setNeedsDisplay]; // [cellContent setNeedsDisplay];
} }
- (void)setupGestures {
- (void) drawContentView:(CGRect)r highlighted:(BOOL)highlighted { [self setDelegate:(NewsBlurViewController <MCSwipeTableViewCellDelegate> *)appDelegate.feedsViewController];
[self setFirstStateIconName:self.isSocial ? @"menu_icn_fetch_subscribers.png" : @"train.png"
firstColor:UIColorFromRGB(0xA4D97B)
secondStateIconName:nil
secondColor:nil
thirdIconName:@"g_icn_unread.png"
thirdColor:UIColorFromRGB(0xFFFFD2)
fourthIconName:nil
fourthColor:nil];
self.mode = MCSwipeTableViewCellModeSwitch;
self.shouldAnimatesIcons = NO;
}
- (void)redrawUnreadCounts {
[((FeedTableCellView *)cellContent) redrawUnreadCounts];
}
@end
@implementation FeedTableCellView
@synthesize cell;
- (void)drawRect:(CGRect)r {
CGContextRef context = UIGraphicsGetCurrentContext(); CGContextRef context = UIGraphicsGetCurrentContext();
UIColor *backgroundColor; UIColor *backgroundColor;
backgroundColor = highlighted ? backgroundColor = cell.highlighted || cell.selected ?
UIColorFromRGB(NEWSBLUR_HIGHLIGHT_COLOR) : UIColorFromRGB(0xFFFFD2) :
self.isSocial ? UIColorFromRGB(0xE6ECE8) : cell.isSocial ? UIColorFromRGB(0xE6ECE8) :
UIColorFromRGB(0xF7F8F5); UIColorFromRGB(0xF7F8F5);
[backgroundColor set]; [backgroundColor set];
CGContextFillRect(context, r); CGContextFillRect(context, r);
if (highlighted) { if (cell.highlighted || cell.selected) {
[NewsBlurAppDelegate fillGradient:r startColor:UIColorFromRGB(0xFFFFD2) endColor:UIColorFromRGB(0xFDED8D)]; // [NewsBlurAppDelegate fillGradient:CGRectMake(r.origin.x, r.origin.y + 1, r.size.width, r.size.height - 1) startColor:UIColorFromRGB(0xFFFFD2) endColor:UIColorFromRGB(0xFDED8D)];
// top border // top border
UIColor *highlightBorderColor = UIColorFromRGB(0xE3D0AE); UIColor *highlightBorderColor = UIColorFromRGB(0xE3D0AE);
CGFloat lineWidth = 0.5f;
CGContextSetStrokeColor(context, CGColorGetComponents([highlightBorderColor CGColor])); CGContextSetStrokeColor(context, CGColorGetComponents([highlightBorderColor CGColor]));
CGContextSetLineWidth(context, lineWidth);
CGContextBeginPath(context); CGContextBeginPath(context);
CGContextMoveToPoint(context, 0, 0.5f); CGContextMoveToPoint(context, 0, lineWidth*0.5f);
CGContextAddLineToPoint(context, r.size.width, 0.5f); CGContextAddLineToPoint(context, r.size.width, 0.5f);
CGContextStrokePath(context); CGContextStrokePath(context);
// bottom border // bottom border
CGContextBeginPath(context); CGContextBeginPath(context);
CGContextMoveToPoint(context, 0, r.size.height - .5f); CGContextSetLineWidth(context, lineWidth);
CGContextAddLineToPoint(context, r.size.width, r.size.height - .5f); CGContextMoveToPoint(context, 0, r.size.height - .5f*lineWidth);
CGContextAddLineToPoint(context, r.size.width, r.size.height - .5f*lineWidth);
CGContextStrokePath(context); CGContextStrokePath(context);
} }
UnreadCountView *unreadCount = [UnreadCountView alloc]; [cell.unreadCount drawInRect:r ps:cell.positiveCount nt:cell.neutralCount
unreadCount.appDelegate = appDelegate; listType:(cell.isSocial ? NBFeedListSocial : NBFeedListFeed)];
[unreadCount drawInRect:r ps:_positiveCount nt:_neutralCount
listType:(isSocial ? NBFeedListSocial : NBFeedListFeed)];
UIColor *textColor = highlighted ? UIColor *textColor = cell.highlighted || cell.selected ?
[UIColor blackColor]: [UIColor blackColor]:
UIColorFromRGB(0x3a3a3a); UIColorFromRGB(0x3a3a3a);
[textColor set];
UIFont *font; UIFont *font;
if (self.negativeCount || self.neutralCount || self.positiveCount) { if (cell.negativeCount || cell.neutralCount || cell.positiveCount) {
font = [UIFont fontWithName:@"HelveticaNeue-Bold" size:13.0]; font = [UIFont fontWithName:@"HelveticaNeue-Bold" size:13.0];
} else { } else {
font = [UIFont fontWithName:@"Helvetica" size:12.6]; font = [UIFont fontWithName:@"Helvetica" size:12.6];
} }
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle defaultParagraphStyle] mutableCopy];
if (isSocial) { paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;
paragraphStyle.alignment = NSTextAlignmentLeft;
if (cell.isSocial) {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[self.feedFavicon drawInRect:CGRectMake(9.0, 2.0, 28.0, 28.0)]; [cell.feedFavicon drawInRect:CGRectMake(9.0, 2.0, 28.0, 28.0)];
[feedTitle [cell.feedTitle drawInRect:CGRectMake(46, 7, r.size.width - ([cell.unreadCount offsetWidth] + 36) - 10 - 16, 20.0)
drawInRect:CGRectMake(46, 7, r.size.width - ([unreadCount offsetWidth] + 36) - 10 - 16, 20.0) withAttributes:@{NSFontAttributeName: font,
withFont:font NSForegroundColorAttributeName: textColor,
lineBreakMode:NSLineBreakByTruncatingTail NSParagraphStyleAttributeName: paragraphStyle}];
alignment:NSTextAlignmentLeft];
} else { } else {
[self.feedFavicon drawInRect:CGRectMake(9.0, 3.0, 26.0, 26.0)]; [cell.feedFavicon drawInRect:CGRectMake(9.0, 3.0, 26.0, 26.0)];
[feedTitle [cell.feedTitle drawInRect:CGRectMake(42, 7, r.size.width - ([cell.unreadCount offsetWidth] + 36) - 10 - 12, 20.0)
drawInRect:CGRectMake(42, 7, r.size.width - ([unreadCount offsetWidth] + 36) - 10 - 12, 20.0) withAttributes:@{NSFontAttributeName: font,
withFont:font NSForegroundColorAttributeName: textColor,
lineBreakMode:NSLineBreakByTruncatingTail NSParagraphStyleAttributeName: paragraphStyle}];
alignment:NSTextAlignmentLeft];
} }
} else { } else {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[self.feedFavicon drawInRect:CGRectMake(12.0, 7.0, 16.0, 16.0)]; [cell.feedFavicon drawInRect:CGRectMake(12.0, 7.0, 16.0, 16.0)];
[feedTitle [cell.feedTitle drawInRect:CGRectMake(36.0, 7.0, r.size.width - ([cell.unreadCount offsetWidth] + 36) - 10, 20.0)
drawInRect:CGRectMake(36.0, 7.0, r.size.width - ([unreadCount offsetWidth] + 36) - 10, 20.0) withAttributes:@{NSFontAttributeName: font,
withFont:font NSForegroundColorAttributeName: textColor,
lineBreakMode:NSLineBreakByTruncatingTail NSParagraphStyleAttributeName: paragraphStyle}];
alignment:NSTextAlignmentLeft];
} else { } else {
[self.feedFavicon drawInRect:CGRectMake(9.0, 7.0, 16.0, 16.0)]; [cell.feedFavicon drawInRect:CGRectMake(9.0, 7.0, 16.0, 16.0)];
[feedTitle [cell.feedTitle drawInRect:CGRectMake(34.0, 7.0, r.size.width - ([cell.unreadCount offsetWidth] + 36) - 10, 20.0)
drawInRect:CGRectMake(34.0, 7.0, r.size.width - ([unreadCount offsetWidth] + 36) - 10, 20.0) withAttributes:@{NSFontAttributeName: font,
withFont:font NSForegroundColorAttributeName: textColor,
lineBreakMode:NSLineBreakByTruncatingTail NSParagraphStyleAttributeName: paragraphStyle}];
alignment:NSTextAlignmentLeft];
} }
} }
} }
- (void)redrawUnreadCounts {
// [cell.unreadCount drawInRect:self.frame ps:cell.positiveCount nt:cell.neutralCount
// listType:(cell.isSocial ? NBFeedListSocial : NBFeedListFeed)];
cell.unreadCount.psCount = cell.positiveCount;
cell.unreadCount.ntCount = cell.neutralCount;
[cell.unreadCount setNeedsLayout];
}
@end @end

View file

@ -102,7 +102,7 @@
return cell; return cell;
} }
- (float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 38; return 38;
} }

View file

@ -200,7 +200,7 @@
} }
- (void)updateSites { - (void)updateSites {
self.instructionLabel.text = [NSString stringWithFormat:@"You are subscribed to %d sites", [[appDelegate.dictFeeds allKeys] count]]; self.instructionLabel.text = [NSString stringWithFormat:@"You are subscribed to %lu sites", (unsigned long)[[appDelegate.dictFeeds allKeys] count]];
NSString *msg = [NSString stringWithFormat:@"Imported %i site%@", NSString *msg = [NSString stringWithFormat:@"Imported %i site%@",
self.importedFeedCount_, self.importedFeedCount_,
self.importedFeedCount_ == 1 ? @"" : @"s"]; self.importedFeedCount_ == 1 ? @"" : @"s"];
@ -366,8 +366,8 @@
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
SiteCell *cell = [tableView SiteCell *cell = [tableView
dequeueReusableCellWithIdentifier:@"ActivityCell"]; dequeueReusableCellWithIdentifier:@"ActivityCell"];
if (cell == nil) { if (cell == nil) {
cell = [[SiteCell alloc] cell = [[SiteCell alloc]
initWithStyle:UITableViewCellStyleDefault initWithStyle:UITableViewCellStyleDefault

View file

@ -13,12 +13,17 @@
@class NewsBlurAppDelegate; @class NewsBlurAppDelegate;
@interface FolderTitleView : UIView { @interface FolderTitleView : UIView
<UIGestureRecognizerDelegate,
UIActionSheetDelegate> {
NewsBlurAppDelegate *appDelegate; NewsBlurAppDelegate *appDelegate;
} }
@property (assign, nonatomic) int section; @property (assign, nonatomic) int section;
@property (nonatomic) NewsBlurAppDelegate *appDelegate; @property (nonatomic) NewsBlurAppDelegate *appDelegate;
@property (nonatomic) UnreadCountView *unreadCount; @property (nonatomic) UnreadCountView *unreadCount;
@property (nonatomic) UIButton *invisibleHeaderButton;
- (void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer;
@end @end

View file

@ -8,6 +8,7 @@
#import <QuartzCore/QuartzCore.h> #import <QuartzCore/QuartzCore.h>
#import "NewsBlurAppDelegate.h" #import "NewsBlurAppDelegate.h"
#import "NewsBlurViewController.h"
#import "FolderTitleView.h" #import "FolderTitleView.h"
#import "UnreadCountView.h" #import "UnreadCountView.h"
@ -16,6 +17,7 @@
@synthesize appDelegate; @synthesize appDelegate;
@synthesize section; @synthesize section;
@synthesize unreadCount; @synthesize unreadCount;
@synthesize invisibleHeaderButton;
- (void)setNeedsDisplay { - (void)setNeedsDisplay {
[unreadCount setNeedsDisplay]; [unreadCount setNeedsDisplay];
@ -25,7 +27,7 @@
- (void) drawRect:(CGRect)rect { - (void) drawRect:(CGRect)rect {
self.appDelegate = (NewsBlurAppDelegate *)[[UIApplication sharedApplication] delegate]; self.appDelegate = [NewsBlurAppDelegate sharedAppDelegate];
NSUserDefaults *userPreferences = [NSUserDefaults standardUserDefaults]; NSUserDefaults *userPreferences = [NSUserDefaults standardUserDefaults];
CGContextRef context = UIGraphicsGetCurrentContext(); CGContextRef context = UIGraphicsGetCurrentContext();
@ -84,21 +86,20 @@
CGContextSetStrokeColor(context, CGColorGetComponents([topColor CGColor])); CGContextSetStrokeColor(context, CGColorGetComponents([topColor CGColor]));
CGContextBeginPath(context); CGContextBeginPath(context);
CGContextMoveToPoint(context, 0, 0.5f); CGContextMoveToPoint(context, 0, 0.25f);
CGContextAddLineToPoint(context, rect.size.width, 0.5f); CGContextAddLineToPoint(context, rect.size.width, 0.25f);
CGContextStrokePath(context); CGContextStrokePath(context);
// bottom border // bottom border
UIColor *bottomColor = UIColorFromRGB(0xB7BBAA); UIColor *bottomColor = UIColorFromRGB(0xB7BBAA);
CGContextSetStrokeColor(context, CGColorGetComponents([bottomColor CGColor])); CGContextSetStrokeColor(context, CGColorGetComponents([bottomColor CGColor]));
CGContextBeginPath(context); CGContextBeginPath(context);
CGContextMoveToPoint(context, 0, rect.size.height - .5f); CGContextMoveToPoint(context, 0, rect.size.height-0.25f);
CGContextAddLineToPoint(context, rect.size.width, rect.size.height - .5f); CGContextAddLineToPoint(context, rect.size.width, rect.size.height-0.25f);
CGContextStrokePath(context); CGContextStrokePath(context);
// Folder title // Folder title
UIColor *textColor = [UIColor colorWithRed:0.3 green:0.3 blue:0.3 alpha:1.0]; UIColor *textColor = [UIColor colorWithRed:0.3 green:0.3 blue:0.3 alpha:1.0];
[textColor set];
UIFont *font = [UIFont boldSystemFontOfSize:11]; UIFont *font = [UIFont boldSystemFontOfSize:11];
NSString *folderTitle; NSString *folderTitle;
if (section == 0) { if (section == 0) {
@ -114,14 +115,17 @@
} }
UIColor *shadowColor = UIColorFromRGB(0xF0F2E9); UIColor *shadowColor = UIColorFromRGB(0xF0F2E9);
CGContextSetShadowWithColor(context, CGSizeMake(0, 1), 0, [shadowColor CGColor]); CGContextSetShadowWithColor(context, CGSizeMake(0, 1), 0, [shadowColor CGColor]);
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle defaultParagraphStyle] mutableCopy];
paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;
paragraphStyle.alignment = NSTextAlignmentLeft;
[folderTitle [folderTitle
drawInRect:CGRectMake(36.0, 10, rect.size.width - 36 - 36 - countWidth, 14) drawInRect:CGRectMake(36.0, 10, rect.size.width - 36 - 36 - countWidth, 14)
withFont:font withAttributes:@{NSFontAttributeName: font,
lineBreakMode:NSLineBreakByTruncatingTail NSForegroundColorAttributeName: textColor,
alignment:NSTextAlignmentLeft]; NSParagraphStyleAttributeName: paragraphStyle}];
UIButton *invisibleHeaderButton = [UIButton buttonWithType:UIButtonTypeCustom]; invisibleHeaderButton = [UIButton buttonWithType:UIButtonTypeCustom];
invisibleHeaderButton.frame = CGRectMake(0, 0, customView.frame.size.width, customView.frame.size.height); invisibleHeaderButton.frame = CGRectMake(0, 0, customView.frame.size.width, customView.frame.size.height);
invisibleHeaderButton.alpha = .1; invisibleHeaderButton.alpha = .1;
invisibleHeaderButton.tag = section; invisibleHeaderButton.tag = section;
@ -159,6 +163,7 @@
UIImage *folderImage; UIImage *folderImage;
int folderImageViewX = 10; int folderImageViewX = 10;
BOOL allowLongPress = NO;
if (section == 0) { if (section == 0) {
folderImage = [UIImage imageNamed:@"ak-icon-global.png"]; folderImage = [UIImage imageNamed:@"ak-icon-global.png"];
@ -198,6 +203,7 @@
} else { } else {
folderImageViewX = 7; folderImageViewX = 7;
} }
allowLongPress = YES;
} }
[folderImage drawInRect:CGRectMake(folderImageViewX, 6, 20, 20)]; [folderImage drawInRect:CGRectMake(folderImageViewX, 6, 20, 20)];
@ -208,6 +214,55 @@
} else { } else {
[self addSubview:customView]; [self addSubview:customView];
} }
if (allowLongPress) {
UILongPressGestureRecognizer *longpress = [[UILongPressGestureRecognizer alloc]
initWithTarget:self action:@selector(handleLongPress:)];
longpress.minimumPressDuration = 1.0;
longpress.delegate = self;
[self addGestureRecognizer:longpress];
}
} }
- (void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer {
if (gestureRecognizer.state != UIGestureRecognizerStateBegan) return;
if (section < 2) return;
NSString *folderTitle = [appDelegate.dictFoldersArray objectAtIndex:section];
UIActionSheet *markReadSheet = [[UIActionSheet alloc] initWithTitle:folderTitle
delegate:self
cancelButtonTitle:@"Cancel"
destructiveButtonTitle:@"Mark folder as read"
otherButtonTitles:@"1 day", @"3 days", @"7 days", @"14 days", nil];
markReadSheet.accessibilityValue = folderTitle;
[markReadSheet showInView:appDelegate.feedsViewController.view];
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
NSString *folderTitle = actionSheet.accessibilityValue;
NSArray *feedIds = [appDelegate.dictFolders objectForKey:folderTitle];
switch (buttonIndex) {
case 0:
[appDelegate.feedsViewController markFeedsRead:feedIds cutoffDays:0];
break;
case 1:
[appDelegate.feedsViewController markFeedsRead:feedIds cutoffDays:1];
break;
case 2:
[appDelegate.feedsViewController markFeedsRead:feedIds cutoffDays:3];
break;
case 3:
[appDelegate.feedsViewController markFeedsRead:feedIds cutoffDays:7];
break;
case 4:
[appDelegate.feedsViewController markFeedsRead:feedIds cutoffDays:14];
break;
}
[appDelegate.feedsViewController sectionUntappedOutside:invisibleHeaderButton];
}
@end @end

View file

@ -178,7 +178,7 @@
return cell; return cell;
} }
- (float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return kMenuOptionHeight; return kMenuOptionHeight;
} }
@ -231,11 +231,17 @@
UITableViewCell *cell = [[UITableViewCell alloc] init]; UITableViewCell *cell = [[UITableViewCell alloc] init];
cell.frame = CGRectMake(0, 0, 240, kMenuOptionHeight); cell.frame = CGRectMake(0, 0, 240, kMenuOptionHeight);
cell.selectionStyle = UITableViewCellSelectionStyleNone; cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.separatorInset = UIEdgeInsetsZero;
fontStyleSegment.frame = CGRectMake(8, 4, cell.frame.size.width - 8*2, kMenuOptionHeight - 4*2); fontStyleSegment.frame = CGRectMake(8, 4, cell.frame.size.width - 8*2, kMenuOptionHeight - 4*2);
[fontStyleSegment setTitle:@"Helvetica" forSegmentAtIndex:0]; [fontStyleSegment setTitle:[@"Helvetica" uppercaseString] forSegmentAtIndex:0];
[fontStyleSegment setTitle:@"Georgia" forSegmentAtIndex:1]; [fontStyleSegment setTitle:[@"Georgia" uppercaseString] forSegmentAtIndex:1];
[fontStyleSegment setTintColor:UIColorFromRGB(0x738570)]; [fontStyleSegment setTintColor:UIColorFromRGB(0x738570)];
[fontStyleSegment
setTitleTextAttributes:@{NSFontAttributeName:
[UIFont fontWithName:@"Helvetica-Bold" size:11.0f]}
forState:UIControlStateNormal];
[fontStyleSegment setContentOffset:CGSizeMake(0, 1) forSegmentAtIndex:0];
[fontStyleSegment setContentOffset:CGSizeMake(0, 1) forSegmentAtIndex:1];
[cell addSubview:fontStyleSegment]; [cell addSubview:fontStyleSegment];
@ -246,6 +252,7 @@
UITableViewCell *cell = [[UITableViewCell alloc] init]; UITableViewCell *cell = [[UITableViewCell alloc] init];
cell.frame = CGRectMake(0, 0, 240, kMenuOptionHeight); cell.frame = CGRectMake(0, 0, 240, kMenuOptionHeight);
cell.selectionStyle = UITableViewCellSelectionStyleNone; cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.separatorInset = UIEdgeInsetsZero;
fontSizeSegment.frame = CGRectMake(8, 4, cell.frame.size.width - 8*2, kMenuOptionHeight - 4*2); fontSizeSegment.frame = CGRectMake(8, 4, cell.frame.size.width - 8*2, kMenuOptionHeight - 4*2);
[fontSizeSegment setTitle:@"12pt" forSegmentAtIndex:0]; [fontSizeSegment setTitle:@"12pt" forSegmentAtIndex:0];
@ -254,6 +261,15 @@
[fontSizeSegment setTitle:@"15pt" forSegmentAtIndex:3]; [fontSizeSegment setTitle:@"15pt" forSegmentAtIndex:3];
[fontSizeSegment setTitle:@"17pt" forSegmentAtIndex:4]; [fontSizeSegment setTitle:@"17pt" forSegmentAtIndex:4];
[fontSizeSegment setTintColor:UIColorFromRGB(0x738570)]; [fontSizeSegment setTintColor:UIColorFromRGB(0x738570)];
[fontSizeSegment
setTitleTextAttributes:@{NSFontAttributeName:
[UIFont fontWithName:@"Helvetica-Bold" size:11.0f]}
forState:UIControlStateNormal];
[fontSizeSegment setContentOffset:CGSizeMake(0, 1) forSegmentAtIndex:0];
[fontSizeSegment setContentOffset:CGSizeMake(0, 1) forSegmentAtIndex:1];
[fontSizeSegment setContentOffset:CGSizeMake(0, 1) forSegmentAtIndex:2];
[fontSizeSegment setContentOffset:CGSizeMake(0, 1) forSegmentAtIndex:3];
[fontSizeSegment setContentOffset:CGSizeMake(0, 1) forSegmentAtIndex:4];
[cell addSubview:fontSizeSegment]; [cell addSubview:fontSizeSegment];

View file

@ -56,7 +56,7 @@
self.appDelegate = (NewsBlurAppDelegate *)[[UIApplication sharedApplication] delegate]; self.appDelegate = (NewsBlurAppDelegate *)[[UIApplication sharedApplication] delegate];
self.view.frame = CGRectMake(0, 0, 320, 416); self.view.frame = CGRectMake(0, 0, 320, 416);
self.contentSizeForViewInPopover = self.view.frame.size; self.preferredContentSize = self.view.frame.size;
} }
- (void)viewDidUnload - (void)viewDidUnload
@ -273,10 +273,10 @@ viewForHeaderInSection:(NSInteger)section {
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (self.inSearch_){ if (self.inSearch_){
int userCount = [self.userProfiles count]; NSInteger userCount = [self.userProfiles count];
return userCount; return userCount;
} else { } else {
int userCount = [self.suggestedUserProfiles count]; NSInteger userCount = [self.suggestedUserProfiles count];
if (!userCount) { if (!userCount) {
return 3; return 3;
} }
@ -304,7 +304,7 @@ viewForHeaderInSection:(NSInteger)section {
if (self.inSearch_){ if (self.inSearch_){
int userProfileCount = [self.userProfiles count]; NSInteger userProfileCount = [self.userProfiles count];
if (userProfileCount) { if (userProfileCount) {
if (userProfileCount > indexPath.row) { if (userProfileCount > indexPath.row) {
@ -379,7 +379,7 @@ viewForHeaderInSection:(NSInteger)section {
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath { - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
NSInteger currentRow = indexPath.row; NSInteger currentRow = indexPath.row;
int row = currentRow; NSInteger row = currentRow;
appDelegate.activeUserProfileId = [[self.userProfiles objectAtIndex:row] objectForKey:@"user_id"]; appDelegate.activeUserProfileId = [[self.userProfiles objectAtIndex:row] objectForKey:@"user_id"];
appDelegate.activeUserProfileName = [[self.userProfiles objectAtIndex:row] objectForKey:@"username"]; appDelegate.activeUserProfileName = [[self.userProfiles objectAtIndex:row] objectForKey:@"username"];
[self.friendSearchBar resignFirstResponder]; [self.friendSearchBar resignFirstResponder];

View file

@ -25,6 +25,7 @@
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
interactionLabel = nil; interactionLabel = nil;
avatarView = nil; avatarView = nil;
self.separatorInset = UIEdgeInsetsMake(0, 90, 0, 0);
// create the label and the avatar // create the label and the avatar
UIImageView *avatar = [[UIImageView alloc] initWithFrame:CGRectZero]; UIImageView *avatar = [[UIImageView alloc] initWithFrame:CGRectZero];
@ -55,16 +56,19 @@
[super layoutSubviews]; [super layoutSubviews];
// determine outer bounds // determine outer bounds
CGRect contentRect = self.contentView.bounds;
// position label to bounds
CGRect labelRect = contentRect;
labelRect.origin.x = labelRect.origin.x + leftMargin + avatarSize + leftMargin;
labelRect.origin.y = labelRect.origin.y + topMargin - 1;
labelRect.size.width = contentRect.size.width - leftMargin - avatarSize - leftMargin - rightMargin;
labelRect.size.height = contentRect.size.height - topMargin - bottomMargin;
self.interactionLabel.frame = labelRect;
[self.interactionLabel sizeToFit]; [self.interactionLabel sizeToFit];
CGRect contentRect = self.frame;
CGRect labelFrame = self.interactionLabel.frame;
// position avatar to bounds
self.avatarView.frame = CGRectMake(leftMargin, topMargin, avatarSize, avatarSize);
// position label to bounds
labelFrame.origin.x = leftMargin*2 + avatarSize;
labelFrame.origin.y = topMargin - 1;
labelFrame.size.width = contentRect.size.width - leftMargin - avatarSize - leftMargin - rightMargin - 20;
labelFrame.size.height = contentRect.size.height - topMargin - bottomMargin;
self.interactionLabel.frame = labelFrame;
} }
@ -113,11 +117,12 @@
NSString *txtWithTime = [NSString stringWithFormat:@"%@\n \n%@", txt, time]; NSString *txtWithTime = [NSString stringWithFormat:@"%@\n \n%@", txt, time];
NSMutableAttributedString* attrStr = [[NSMutableAttributedString alloc] initWithString:txtWithTime]; NSMutableAttributedString* attrStr = [[NSMutableAttributedString alloc] initWithString:txtWithTime];
NSMutableParagraphStyle* style = [NSMutableParagraphStyle new]; NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle defaultParagraphStyle] mutableCopy];
style.lineBreakMode = NSLineBreakByWordWrapping; paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
style.alignment = NSTextAlignmentLeft; paragraphStyle.alignment = NSTextAlignmentLeft;
style.lineSpacing = 1.0f; paragraphStyle.lineSpacing = 1.0f;
[attrStr setAttributes:@{NSParagraphStyleAttributeName: style} range:NSMakeRange(0, [txtWithTime length])]; [attrStr setAttributes:@{NSParagraphStyleAttributeName: paragraphStyle}
range:NSMakeRange(0, [txtWithTime length])];
[attrStr addAttributes:@{NSFontAttributeName:[UIFont fontWithName:@"Helvetica" size:13]} range:NSMakeRange(0, [txtWithTime length])]; [attrStr addAttributes:@{NSFontAttributeName:[UIFont fontWithName:@"Helvetica" size:13]} range:NSMakeRange(0, [txtWithTime length])];
if (self.highlighted) { if (self.highlighted) {

View file

@ -180,7 +180,7 @@
} }
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
int userInteractions = [appDelegate.userInteractionsArray count]; NSInteger userInteractions = [appDelegate.userInteractionsArray count];
int minimumHeight; int minimumHeight;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
minimumHeight = MINIMUM_INTERACTION_HEIGHT_IPAD; minimumHeight = MINIMUM_INTERACTION_HEIGHT_IPAD;
@ -210,7 +210,7 @@
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{ {
int userInteractionsCount = [appDelegate.userInteractionsArray count]; NSInteger userInteractionsCount = [appDelegate.userInteractionsArray count];
return userInteractionsCount + 1; return userInteractionsCount + 1;
} }
@ -246,7 +246,7 @@
} }
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
int userInteractions = [appDelegate.userInteractionsArray count]; NSInteger userInteractions = [appDelegate.userInteractionsArray count];
if (indexPath.row < userInteractions) { if (indexPath.row < userInteractions) {
NSDictionary *interaction = [appDelegate.userInteractionsArray objectAtIndex:indexPath.row]; NSDictionary *interaction = [appDelegate.userInteractionsArray objectAtIndex:indexPath.row];
NSString *category = [interaction objectForKey:@"category"]; NSString *category = [interaction objectForKey:@"category"];

View file

@ -48,7 +48,12 @@
self.emailInput.borderStyle = UITextBorderStyleRoundedRect; self.emailInput.borderStyle = UITextBorderStyleRoundedRect;
self.signUpPasswordInput.borderStyle = UITextBorderStyleRoundedRect; self.signUpPasswordInput.borderStyle = UITextBorderStyleRoundedRect;
self.signUpUsernameInput.borderStyle = UITextBorderStyleRoundedRect; self.signUpUsernameInput.borderStyle = UITextBorderStyleRoundedRect;
[self.loginControl
setTitleTextAttributes:@{NSFontAttributeName:
[UIFont fontWithName:@"Helvetica-Bold" size:11.0f]}
forState:UIControlStateNormal];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation)) { if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation)) {
self.logInView.frame = CGRectMake(134, 180, 500, 300); self.logInView.frame = CGRectMake(134, 180, 500, 300);
@ -218,6 +223,7 @@
[self.passwordInput setText:@""]; [self.passwordInput setText:@""];
[self.signUpPasswordInput setText:@""]; [self.signUpPasswordInput setText:@""];
[appDelegate reloadFeedsView:YES]; [appDelegate reloadFeedsView:YES];
[self dismissViewControllerAnimated:YES completion:nil];
} }
} }
@ -278,7 +284,7 @@
[self.signUpPasswordInput setText:@""]; [self.signUpPasswordInput setText:@""];
// [appDelegate showFirstTimeUser]; // [appDelegate showFirstTimeUser];
[appDelegate reloadFeedsView:YES]; [appDelegate reloadFeedsView:YES];
[self dismissViewControllerAnimated:NO completion:nil]; [self dismissViewControllerAnimated:YES completion:nil];
} }
} }
@ -357,6 +363,7 @@
// Login // Login
usernameInput.frame = CGRectMake(20, 67, 280, 31); usernameInput.frame = CGRectMake(20, 67, 280, 31);
usernameOrEmailLabel.alpha = 1.0; usernameOrEmailLabel.alpha = 1.0;
usernameLabel.alpha = 0.0;
passwordInput.frame = CGRectMake(20, 129, 280, 31); passwordInput.frame = CGRectMake(20, 129, 280, 31);
passwordLabel.frame = CGRectMake(21, 106, 212, 22); passwordLabel.frame = CGRectMake(21, 106, 212, 22);
@ -375,6 +382,7 @@
// Signup // Signup
usernameInput.frame = CGRectMake(20, 67, 130, 31); usernameInput.frame = CGRectMake(20, 67, 130, 31);
usernameOrEmailLabel.alpha = 0.0; usernameOrEmailLabel.alpha = 0.0;
usernameLabel.alpha = 1.0;
passwordInput.frame = CGRectMake(170, 67, 130, 31); passwordInput.frame = CGRectMake(170, 67, 130, 31);
passwordLabel.frame = CGRectMake(171, 44, 212, 22); passwordLabel.frame = CGRectMake(171, 44, 212, 22);

View file

@ -21,6 +21,7 @@
self.textLabel.shadowColor = UIColorFromRGB(0xF0F0F0); self.textLabel.shadowColor = UIColorFromRGB(0xF0F0F0);
self.textLabel.shadowOffset = CGSizeMake(0, 1); self.textLabel.shadowOffset = CGSizeMake(0, 1);
self.textLabel.font = [UIFont fontWithName:@"Helvetica-Bold" size:14.0]; self.textLabel.font = [UIFont fontWithName:@"Helvetica-Bold" size:14.0];
[self setSeparatorInset:UIEdgeInsetsMake(0, 38, 0, 0)];
UIView *background = [[UIView alloc] init]; UIView *background = [[UIView alloc] init];
[background setBackgroundColor:UIColorFromRGB(0xFFFFFF)]; [background setBackgroundColor:UIColorFromRGB(0xFFFFFF)];
[self setBackgroundView:background]; [self setBackgroundView:background];

View file

@ -29,7 +29,7 @@
- (NSArray *)pickerFolders; - (NSArray *)pickerFolders;
@property (nonatomic) IBOutlet NewsBlurAppDelegate *appDelegate; @property (nonatomic) IBOutlet NewsBlurAppDelegate *appDelegate;
@property (nonatomic) IBOutlet FolderTextField *fromFolderInput; @property (nonatomic) IBOutlet UITextField *fromFolderInput;
@property (nonatomic) IBOutlet FolderTextField *toFolderInput; @property (nonatomic) IBOutlet FolderTextField *toFolderInput;
@property (nonatomic) IBOutlet UILabel *titleLabel; @property (nonatomic) IBOutlet UILabel *titleLabel;

View file

@ -36,15 +36,22 @@
- (void)viewDidLoad { - (void)viewDidLoad {
UIImageView *folderImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"g_icn_folder.png"]]; UIImageView *folderImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"g_icn_folder.png"]];
folderImage.frame = CGRectMake(-6, 0, 16, 16); folderImage.frame = CGRectMake(0, 0, 24, 16);
[folderImage setContentMode:UIViewContentModeRight];
[toFolderInput setLeftView:folderImage]; [toFolderInput setLeftView:folderImage];
[toFolderInput setLeftViewMode:UITextFieldViewModeAlways]; [toFolderInput setLeftViewMode:UITextFieldViewModeAlways];
UIImageView *folderImage2 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"g_icn_folder_rss.png"]]; UIImageView *folderImage2 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"g_icn_folder_rss.png"]];
folderImage2.frame = CGRectMake(-6, 0, 16, 16); folderImage2.frame = CGRectMake(0, 0, 24, 16);
[folderImage2 setContentMode:UIViewContentModeRight];
[fromFolderInput setLeftView:folderImage2]; [fromFolderInput setLeftView:folderImage2];
[fromFolderInput setLeftViewMode:UITextFieldViewModeAlways]; [fromFolderInput setLeftViewMode:UITextFieldViewModeAlways];
navBar.tintColor = [UIColor colorWithRed:0.16f green:0.36f blue:0.46 alpha:0.9]; navBar.tintColor = [UIColor colorWithRed:0.16f green:0.36f blue:0.46 alpha:0.9];
CGRect frame = self.navBar.frame;
frame.size.height += 20;
self.navBar.frame = frame;
appDelegate = [NewsBlurAppDelegate sharedAppDelegate]; appDelegate = [NewsBlurAppDelegate sharedAppDelegate];
@ -71,7 +78,7 @@
[subview removeFromSuperview]; [subview removeFromSuperview];
} }
UIView *label = [appDelegate makeFeedTitle:appDelegate.activeFeed]; UIView *label = [appDelegate makeFeedTitle:appDelegate.activeFeed];
label.frame = CGRectMake(0, label.frame = CGRectMake(8,
0, 0,
200, 200,
20); 20);
@ -89,7 +96,7 @@
- (void)reload { - (void)reload {
BOOL isTopLevel = [[appDelegate.activeFolder trim] isEqualToString:@""] || BOOL isTopLevel = [[appDelegate.activeFolder trim] isEqualToString:@""] ||
[appDelegate.activeFolder isEqual:@"everything"]; [appDelegate.activeFolder isEqual:@"everything"];
int row = 0; NSInteger row = 0;
[toFolderInput setText:@""]; [toFolderInput setText:@""];
if (appDelegate.isRiverView) { if (appDelegate.isRiverView) {
@ -295,15 +302,11 @@ numberOfRowsInComponent:(NSInteger)component {
@implementation FolderTextField @implementation FolderTextField
- (CGRect)textRectForBounds:(CGRect)bounds { - (CGRect)textRectForBounds:(CGRect)bounds {
int margin = 18; return CGRectInset(bounds, 24, 0);
CGRect inset = CGRectMake(bounds.origin.x + margin, bounds.origin.y, bounds.size.width - margin, bounds.size.height);
return inset;
} }
- (CGRect)editingRectForBounds:(CGRect)bounds { - (CGRect)editingRectForBounds:(CGRect)bounds {
int margin = 18; return CGRectInset(bounds, 24, 0);
CGRect inset = CGRectMake(bounds.origin.x + margin, bounds.origin.y, bounds.size.width - margin, bounds.size.height);
return inset;
} }
@end @end

View file

@ -0,0 +1,15 @@
//
// NBBarButtonItem.h
// NewsBlur
//
// Created by Samuel Clay on 9/24/13.
// Copyright (c) 2013 NewsBlur. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface NBBarButtonItem : UIButton
@property (nonatomic, assign) BOOL onRightSide;
@end

View file

@ -0,0 +1,29 @@
//
// NBBarButtonItem.m
// NewsBlur
//
// Created by Samuel Clay on 9/24/13.
// Copyright (c) 2013 NewsBlur. All rights reserved.
//
#import "NBBarButtonItem.h"
@implementation NBBarButtonItem
@synthesize onRightSide;
- (UIEdgeInsets)alignmentRectInsets {
UIEdgeInsets insets;
if (![self isLeftButton] || self.onRightSide) {
insets = UIEdgeInsetsMake(0, 0, 0, 8.0f);
} else {
insets = UIEdgeInsetsMake(0, 8.0f, 0, 0);
}
return insets;
}
- (BOOL)isLeftButton {
return self.frame.origin.x < (self.window.frame.size.width / 2);
}
@end

View file

@ -16,6 +16,7 @@
#import "UserProfileViewController.h" #import "UserProfileViewController.h"
#import "InteractionCell.h" #import "InteractionCell.h"
#import "ActivityCell.h" #import "ActivityCell.h"
#import "FeedTableCell.h"
#import "FeedsMenuViewController.h" #import "FeedsMenuViewController.h"
#import "FeedDetailMenuViewController.h" #import "FeedDetailMenuViewController.h"
#import "FontSettingsViewController.h" #import "FontSettingsViewController.h"
@ -25,8 +26,8 @@
#define NB_DEFAULT_MASTER_WIDTH 270 #define NB_DEFAULT_MASTER_WIDTH 270
#define NB_DEFAULT_STORY_TITLE_HEIGHT 1004 #define NB_DEFAULT_STORY_TITLE_HEIGHT 1004
#define NB_DEFAULT_SLIDER_INTERVAL 0.35 #define NB_DEFAULT_SLIDER_INTERVAL 0.3
#define NB_DEFAULT_SLIDER_INTERVAL_OUT 0.35 #define NB_DEFAULT_SLIDER_INTERVAL_OUT 0.3
#define NB_DEFAULT_SHARE_HEIGHT 144 #define NB_DEFAULT_SHARE_HEIGHT 144
#define NB_DEFAULT_STORY_TITLE_SNAP_THRESHOLD 60 #define NB_DEFAULT_STORY_TITLE_SNAP_THRESHOLD 60
@ -99,6 +100,8 @@
object:nil]; object:nil];
self.view.backgroundColor = UIColorFromRGB(0xC2C5BE); self.view.backgroundColor = UIColorFromRGB(0xC2C5BE);
self.navigationController.navigationBar.translucent = NO;
self.masterNavigationController.navigationBar.translucent = NO;
self.masterNavigationController = appDelegate.navigationController; self.masterNavigationController = appDelegate.navigationController;
self.feedsViewController = appDelegate.feedsViewController; self.feedsViewController = appDelegate.feedsViewController;
@ -120,9 +123,11 @@
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:self.storyPageControl]; UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:self.storyPageControl];
self.storyNavigationController = nav; self.storyNavigationController = nav;
self.storyNavigationController.navigationBar.translucent = NO;
UINavigationController *shareNav = [[UINavigationController alloc] initWithRootViewController:self.shareViewController]; UINavigationController *shareNav = [[UINavigationController alloc] initWithRootViewController:self.shareViewController];
self.shareNavigationController = shareNav; self.shareNavigationController = shareNav;
self.shareNavigationController.navigationBar.translucent = NO;
// set default y coordinate for feedDetailY from saved preferences // set default y coordinate for feedDetailY from saved preferences
NSUserDefaults *userPreferences = [NSUserDefaults standardUserDefaults]; NSUserDefaults *userPreferences = [NSUserDefaults standardUserDefaults];
@ -140,12 +145,12 @@
// set up story titles stub // set up story titles stub
UIView * storyTitlesPlaceholder = [[UIView alloc] initWithFrame:CGRectZero]; UIView * storyTitlesPlaceholder = [[UIView alloc] initWithFrame:CGRectZero];
storyTitlesPlaceholder.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;; storyTitlesPlaceholder.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
storyTitlesPlaceholder.autoresizesSubviews = YES; storyTitlesPlaceholder.autoresizesSubviews = YES;
storyTitlesPlaceholder.backgroundColor = [UIColor whiteColor]; storyTitlesPlaceholder.backgroundColor = [UIColor whiteColor];
self.storyTitlesStub = storyTitlesPlaceholder; self.storyTitlesStub = storyTitlesPlaceholder;
[self.view addSubview:self.storyTitlesStub]; [self.view insertSubview:self.storyTitlesStub aboveSubview:self.storyNavigationController.view];
} }
- (void)viewWillLayoutSubviews { - (void)viewWillLayoutSubviews {
@ -202,10 +207,17 @@
[sender class] == [ActivityCell class]) { [sender class] == [ActivityCell class]) {
InteractionCell *cell = (InteractionCell *)sender; InteractionCell *cell = (InteractionCell *)sender;
[popoverController presentPopoverFromRect:cell.bounds [popoverController presentPopoverFromRect:cell.bounds
inView:cell inView:cell
permittedArrowDirections:UIPopoverArrowDirectionAny permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES]; animated:YES];
} else if ([sender class] == [FeedTableCell class]) {
FeedTableCell *cell = (FeedTableCell *)sender;
[popoverController presentPopoverFromRect:cell.bounds
inView:cell
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
} else if ([sender class] == [UIBarButtonItem class]) { } else if ([sender class] == [UIBarButtonItem class]) {
[popoverController presentPopoverFromBarButtonItem:sender [popoverController presentPopoverFromBarButtonItem:sender
permittedArrowDirections:UIPopoverArrowDirectionAny permittedArrowDirections:UIPopoverArrowDirectionAny
@ -246,7 +258,7 @@
popoverController = [[UIPopoverController alloc] popoverController = [[UIPopoverController alloc]
initWithContentViewController:appDelegate.feedsMenuViewController]; initWithContentViewController:appDelegate.feedsMenuViewController];
[popoverController setDelegate:self]; [popoverController setDelegate:self];
int menuCount = [appDelegate.feedsMenuViewController.menuOptions count]; NSInteger menuCount = [appDelegate.feedsMenuViewController.menuOptions count];
[popoverController setPopoverContentSize:CGSizeMake(200, 38 * menuCount)]; [popoverController setPopoverContentSize:CGSizeMake(200, 38 * menuCount)];
[popoverController presentPopoverFromBarButtonItem:sender [popoverController presentPopoverFromBarButtonItem:sender
permittedArrowDirections:UIPopoverArrowDirectionAny permittedArrowDirections:UIPopoverArrowDirectionAny
@ -266,7 +278,7 @@
[appDelegate.feedDetailMenuViewController buildMenuOptions]; [appDelegate.feedDetailMenuViewController buildMenuOptions];
popoverController.delegate = self; popoverController.delegate = self;
int menuCount = [appDelegate.feedDetailMenuViewController.menuOptions count] + 2; NSInteger menuCount = [appDelegate.feedDetailMenuViewController.menuOptions count] + 2;
[popoverController setPopoverContentSize:CGSizeMake(260, 38 * menuCount)]; [popoverController setPopoverContentSize:CGSizeMake(260, 38 * menuCount)];
[popoverController presentPopoverFromBarButtonItem:sender [popoverController presentPopoverFromBarButtonItem:sender
permittedArrowDirections:UIPopoverArrowDirectionAny permittedArrowDirections:UIPopoverArrowDirectionAny
@ -308,6 +320,12 @@
[popoverController presentPopoverFromBarButtonItem:sender [popoverController presentPopoverFromBarButtonItem:sender
permittedArrowDirections:UIPopoverArrowDirectionAny permittedArrowDirections:UIPopoverArrowDirectionAny
animated:NO]; animated:NO];
} else if ([sender class] == [FeedTableCell class]) {
FeedTableCell *cell = (FeedTableCell *)sender;
[popoverController presentPopoverFromRect:cell.bounds
inView:cell
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
} else { } else {
CGRect frame = [sender CGRectValue]; CGRect frame = [sender CGRectValue];
[popoverController presentPopoverFromRect:frame [popoverController presentPopoverFromRect:frame
@ -361,7 +379,7 @@
- (void)adjustFeedDetailScreen { - (void)adjustFeedDetailScreen {
CGRect vb = [self.view bounds]; CGRect vb = [self.view bounds];
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if (UIInterfaceOrientationIsPortrait(orientation) && !self.storyTitlesOnLeft) { if (UIInterfaceOrientationIsPortrait(orientation) && !self.storyTitlesOnLeft) {
// add the back button // add the back button
@ -382,9 +400,6 @@
// remove the back button // remove the back button
self.storyPageControl.navigationItem.leftBarButtonItem = nil; self.storyPageControl.navigationItem.leftBarButtonItem = nil;
// remove center title
self.storyPageControl.navigationItem.titleView = nil;
if (![[self.masterNavigationController viewControllers] containsObject:self.feedDetailViewController]) { if (![[self.masterNavigationController viewControllers] containsObject:self.feedDetailViewController]) {
[self.masterNavigationController pushViewController:self.feedDetailViewController animated:NO]; [self.masterNavigationController pushViewController:self.feedDetailViewController animated:NO];
} }
@ -396,6 +411,7 @@
- (void)adjustFeedDetailScreenForStoryTitles { - (void)adjustFeedDetailScreenForStoryTitles {
CGRect vb = [self.view bounds]; CGRect vb = [self.view bounds];
if (!self.storyTitlesOnLeft) { if (!self.storyTitlesOnLeft) {
if (self.storyTitlesYCoordinate > 890) { if (self.storyTitlesYCoordinate > 890) {
NSUserDefaults *userPreferences = [NSUserDefaults standardUserDefaults]; NSUserDefaults *userPreferences = [NSUserDefaults standardUserDefaults];
@ -411,7 +427,7 @@
self.storyPageControl.navigationItem.leftBarButtonItem = nil; self.storyPageControl.navigationItem.leftBarButtonItem = nil;
// remove center title // remove center title
self.storyPageControl.navigationItem.titleView = nil; // self.storyPageControl.navigationItem.titleView = nil;
if (![[self.masterNavigationController viewControllers] containsObject:self.feedDetailViewController]) { if (![[self.masterNavigationController viewControllers] containsObject:self.feedDetailViewController]) {
[self.masterNavigationController pushViewController:self.feedDetailViewController animated:NO]; [self.masterNavigationController pushViewController:self.feedDetailViewController animated:NO];
@ -445,8 +461,8 @@
self.storyPageControl.navigationItem.leftBarButtonItem = self.storyPageControl.buttonBack; self.storyPageControl.navigationItem.leftBarButtonItem = self.storyPageControl.buttonBack;
// set center title // set center title
UIView *titleLabel = [appDelegate makeFeedTitle:appDelegate.activeFeed]; // UIView *titleLabel = [appDelegate makeFeedTitle:appDelegate.activeFeed];
self.storyPageControl.navigationItem.titleView = titleLabel; // self.storyPageControl.navigationItem.titleView = titleLabel;
[UIView animateWithDuration:NB_DEFAULT_SLIDER_INTERVAL delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ [UIView animateWithDuration:NB_DEFAULT_SLIDER_INTERVAL delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
// self.masterNavigationController.view.frame = CGRectMake(-NB_DEFAULT_MASTER_WIDTH, 0, NB_DEFAULT_MASTER_WIDTH, vb.size.height); // self.masterNavigationController.view.frame = CGRectMake(-NB_DEFAULT_MASTER_WIDTH, 0, NB_DEFAULT_MASTER_WIDTH, vb.size.height);
@ -488,49 +504,50 @@
// reset the storyDetailViewController components // reset the storyDetailViewController components
self.storyPageControl.currentPage.webView.hidden = YES; self.storyPageControl.currentPage.webView.hidden = YES;
self.storyPageControl.nextPage.webView.hidden = YES; self.storyPageControl.nextPage.webView.hidden = YES;
self.storyPageControl.bottomPlaceholderToolbar.hidden = NO; self.storyPageControl.bottomSize.hidden = NO;
self.storyPageControl.navigationItem.rightBarButtonItems = nil; self.storyPageControl.navigationItem.rightBarButtonItems = nil;
[self.storyPageControl resetPages]; [self.storyPageControl hidePages];
int unreadCount = appDelegate.unreadCount; NSInteger unreadCount = appDelegate.unreadCount;
if (unreadCount == 0) { if (unreadCount == 0) {
self.storyPageControl.circularProgressView.percentage = 1; self.storyPageControl.circularProgressView.percentage = 1;
} else { } else {
self.storyPageControl.circularProgressView.percentage = 0; self.storyPageControl.circularProgressView.percentage = 0;
} }
// UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; UIView *titleLabel = [appDelegate makeFeedTitle:appDelegate.activeFeed];
// if (NO && UIInterfaceOrientationIsPortrait(orientation) && !self.storyTitlesOnLeft) { self.storyPageControl.navigationItem.titleView = titleLabel;
// // CASE: story titles on bottom
// self.storyPageControl.navigationItem.leftBarButtonItem = self.storyPageControl.buttonBack; UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
// if (UIInterfaceOrientationIsPortrait(orientation) && !self.storyTitlesOnLeft) {
// self.storyNavigationController.view.frame = CGRectMake(vb.size.width, 0, vb.size.width, storyTitlesYCoordinate); // CASE: story titles on bottom
// self.feedDetailViewController.view.frame = CGRectMake(vb.size.width, self.storyPageControl.navigationItem.leftBarButtonItem = self.storyPageControl.buttonBack;
// self.storyTitlesYCoordinate, self.storyPageControl.navigationItem.rightBarButtonItems = self.feedDetailViewController.navigationItem.rightBarButtonItems;
// vb.size.width,
// vb.size.height - storyTitlesYCoordinate); self.storyNavigationController.view.frame = CGRectMake(vb.size.width, 0, vb.size.width, storyTitlesYCoordinate);
// float largeTimeInterval = NB_DEFAULT_SLIDER_INTERVAL * ( vb.size.width - NB_DEFAULT_MASTER_WIDTH) / vb.size.width; self.feedDetailViewController.view.frame = CGRectMake(vb.size.width,
// float smallTimeInterval = NB_DEFAULT_SLIDER_INTERVAL * NB_DEFAULT_MASTER_WIDTH / vb.size.width; self.storyTitlesYCoordinate,
// vb.size.width,
// [UIView animateWithDuration:largeTimeInterval delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{ vb.size.height - storyTitlesYCoordinate);
// self.storyNavigationController.view.frame = CGRectMake(NB_DEFAULT_MASTER_WIDTH + 1, 0, vb.size.width, self.storyTitlesYCoordinate); float largeTimeInterval = NB_DEFAULT_SLIDER_INTERVAL * ( vb.size.width - NB_DEFAULT_MASTER_WIDTH) / vb.size.width;
// self.feedDetailViewController.view.frame = CGRectMake(NB_DEFAULT_MASTER_WIDTH + 1, float smallTimeInterval = NB_DEFAULT_SLIDER_INTERVAL * NB_DEFAULT_MASTER_WIDTH / vb.size.width;
// self.storyTitlesYCoordinate,
// vb.size.width, [UIView animateWithDuration:largeTimeInterval delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
// vb.size.height - storyTitlesYCoordinate); self.storyNavigationController.view.frame = CGRectMake(NB_DEFAULT_MASTER_WIDTH + 1, 0, vb.size.width, self.storyTitlesYCoordinate);
// } completion:^(BOOL finished) { self.feedDetailViewController.view.frame = CGRectMake(NB_DEFAULT_MASTER_WIDTH + 1,
// [UIView animateWithDuration:smallTimeInterval delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{ self.storyTitlesYCoordinate,
// self.storyNavigationController.view.frame = CGRectMake(0, 0, vb.size.width, self.storyTitlesYCoordinate); vb.size.width,
// self.feedDetailViewController.view.frame = CGRectMake(0, self.storyTitlesYCoordinate, vb.size.width, vb.size.height - storyTitlesYCoordinate); vb.size.height - storyTitlesYCoordinate);
// self.masterNavigationController.view.frame = CGRectMake(-NB_DEFAULT_MASTER_WIDTH, 0, NB_DEFAULT_MASTER_WIDTH, vb.size.height); } completion:^(BOOL finished) {
// } completion:^(BOOL finished) { [UIView animateWithDuration:smallTimeInterval delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
// [self.dashboardViewController.view removeFromSuperview]; self.storyNavigationController.view.frame = CGRectMake(0, 0, vb.size.width, self.storyTitlesYCoordinate);
// [self.masterNavigationController.view removeFromSuperview]; self.feedDetailViewController.view.frame = CGRectMake(0, self.storyTitlesYCoordinate, vb.size.width, vb.size.height - storyTitlesYCoordinate);
// }]; self.masterNavigationController.view.frame = CGRectMake(-NB_DEFAULT_MASTER_WIDTH, 0, NB_DEFAULT_MASTER_WIDTH, vb.size.height);
// }]; } completion:^(BOOL finished) {
// [self.dashboardViewController.view removeFromSuperview];
// UIView *titleLabel = [appDelegate makeFeedTitle:appDelegate.activeFeed]; [self.masterNavigationController.view removeFromSuperview];
// self.storyPageControl.navigationItem.titleView = titleLabel; }];
// } else { }];
} else {
// CASE: story titles on left // CASE: story titles on left
[self.masterNavigationController [self.masterNavigationController
pushViewController:self.feedDetailViewController pushViewController:self.feedDetailViewController
@ -548,9 +565,10 @@
[self.dashboardViewController.view removeFromSuperview]; [self.dashboardViewController.view removeFromSuperview];
}]; }];
self.storyPageControl.navigationItem.titleView = nil; // self.storyPageControl.navigationItem.titleView = nil;
self.storyPageControl.navigationItem.leftBarButtonItem = nil; self.storyPageControl.navigationItem.leftBarButtonItem = nil;
// } self.storyPageControl.navigationItem.rightBarButtonItem = nil;
}
} }
- (void)transitionFromFeedDetail { - (void)transitionFromFeedDetail {
@ -693,11 +711,12 @@
CGRect vb = [self.view bounds]; CGRect vb = [self.view bounds];
// account for top toolbar and status bar // account for top toolbar and status bar
yCoordinate = yCoordinate + 44 + 20; yCoordinate = yCoordinate + 64 + 20;
NSUserDefaults *userPreferences = [NSUserDefaults standardUserDefaults]; NSUserDefaults *userPreferences = [NSUserDefaults standardUserDefaults];
if (yCoordinate > 344 && yCoordinate <= (vb.size.height)) { if (yCoordinate <= (vb.size.height)) {
yCoordinate = MAX(yCoordinate, 384);
self.storyTitlesYCoordinate = yCoordinate; self.storyTitlesYCoordinate = yCoordinate;
[userPreferences setInteger:yCoordinate forKey:@"storyTitlesYCoordinate"]; [userPreferences setInteger:yCoordinate forKey:@"storyTitlesYCoordinate"];
[userPreferences synchronize]; [userPreferences synchronize];
@ -735,7 +754,23 @@
0); 0);
} }
} }
UITableView *stories = appDelegate.feedDetailViewController.storyTitlesTable;
NSInteger location = appDelegate.locationOfActiveStory;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:location inSection:0];
NSArray *visible = [stories visibleCells];
for (UITableViewCell *cell in visible) {
if ([stories indexPathForCell:cell].row == indexPath.row) {
indexPath = nil;
break;
}
}
if (indexPath && location >= 0) {
[stories selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionMiddle];
}
[appDelegate.feedDetailViewController.notifier setNeedsLayout];
} }
-(void)keyboardWillShowOrHide:(NSNotification*)notification { -(void)keyboardWillShowOrHide:(NSNotification*)notification {
@ -767,7 +802,7 @@
NB_DEFAULT_SHARE_HEIGHT); NB_DEFAULT_SHARE_HEIGHT);
CGRect shareViewFrame = self.shareNavigationController.view.frame; CGRect shareViewFrame = self.shareNavigationController.view.frame;
if (self.keyboardIsShown) { if (self.keyboardIsShown && self.isSharingStory) {
if (UIInterfaceOrientationIsPortrait(orientation)) { if (UIInterfaceOrientationIsPortrait(orientation)) {
storyNavigationFrame.size.height = vb.size.height - NB_DEFAULT_SHARE_HEIGHT - keyboardFrame.size.height + 44; storyNavigationFrame.size.height = vb.size.height - NB_DEFAULT_SHARE_HEIGHT - keyboardFrame.size.height + 44;
shareViewFrame.origin.y = vb.size.height - NB_DEFAULT_SHARE_HEIGHT - keyboardFrame.size.height; shareViewFrame.origin.y = vb.size.height - NB_DEFAULT_SHARE_HEIGHT - keyboardFrame.size.height;
@ -775,12 +810,12 @@
storyNavigationFrame.size.height = vb.size.height - NB_DEFAULT_SHARE_HEIGHT - keyboardFrame.size.width + 44; storyNavigationFrame.size.height = vb.size.height - NB_DEFAULT_SHARE_HEIGHT - keyboardFrame.size.width + 44;
shareViewFrame.origin.y = vb.size.height - NB_DEFAULT_SHARE_HEIGHT - keyboardFrame.size.width; shareViewFrame.origin.y = vb.size.height - NB_DEFAULT_SHARE_HEIGHT - keyboardFrame.size.width;
} }
} else { } else if (self.isSharingStory) {
if (UIInterfaceOrientationIsPortrait(orientation)) { if (UIInterfaceOrientationIsPortrait(orientation)) {
storyNavigationFrame.size.height = vb.size.height - NB_DEFAULT_SHARE_HEIGHT + 44; storyNavigationFrame.size.height = vb.size.height - NB_DEFAULT_SHARE_HEIGHT + 64;
shareViewFrame.origin.y = vb.size.height - NB_DEFAULT_SHARE_HEIGHT; shareViewFrame.origin.y = vb.size.height - NB_DEFAULT_SHARE_HEIGHT;
} else { } else {
storyNavigationFrame.size.height = vb.size.height - NB_DEFAULT_SHARE_HEIGHT + 44; storyNavigationFrame.size.height = vb.size.height - NB_DEFAULT_SHARE_HEIGHT + 64;
shareViewFrame.origin.y = vb.size.height - NB_DEFAULT_SHARE_HEIGHT; shareViewFrame.origin.y = vb.size.height - NB_DEFAULT_SHARE_HEIGHT;
} }
} }
@ -815,7 +850,7 @@
vb.size.height, vb.size.height,
self.storyNavigationController.view.frame.size.width, self.storyNavigationController.view.frame.size.width,
NB_DEFAULT_SHARE_HEIGHT); NB_DEFAULT_SHARE_HEIGHT);
if (UIInterfaceOrientationIsPortrait(orientation)) { if (UIInterfaceOrientationIsPortrait(orientation) && !self.storyTitlesOnLeft) {
self.storyNavigationController.view.frame = CGRectMake(self.storyNavigationController.view.frame.origin.x, self.storyNavigationController.view.frame = CGRectMake(self.storyNavigationController.view.frame.origin.x,
0, 0,
self.storyNavigationController.view.frame.size.width, self.storyNavigationController.view.frame.size.width,

View file

@ -195,6 +195,9 @@
- (void)showIn:(float)time { - (void)showIn:(float)time {
showing = YES; showing = YES;
CGRect frame = self.frame;
frame.size.width = self.view.frame.size.width;
self.frame = frame;
[UIView beginAnimations:nil context:nil]; [UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:time]; [UIView setAnimationDuration:time];

View file

@ -0,0 +1,15 @@
//
// NBSwipeableCell.h
// NewsBlur
//
// Created by Samuel Clay on 9/27/13.
// Copyright (c) 2013 NewsBlur. All rights reserved.
//
#import "MCSwipeTableViewCell.h"
@interface NBSwipeableCell : MCSwipeTableViewCell
- (UIImage *)imageByApplyingAlpha:(UIImage *)image withAlpha:(CGFloat) alpha;
@end

View file

@ -0,0 +1,65 @@
//
// NBSwipeableCell.m
// NewsBlur
//
// Created by Samuel Clay on 9/27/13.
// Copyright (c) 2013 NewsBlur. All rights reserved.
//
#import "NBSwipeableCell.h"
#import "MCSwipeTableViewCell.h"
@implementation NBSwipeableCell
- (void)setNeedsDisplay {
[super setNeedsDisplay];
for (UIView *view in self.contentView.subviews) {
[view setNeedsDisplay];
}
}
- (void)setNeedsLayout {
[super setNeedsLayout];
for (UIView *view in self.contentView.subviews) {
[view setNeedsLayout];
}
}
- (void) setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:NO];
if (animated) {
[CATransaction begin];
CATransition* animation = [CATransition animation];
animation.type = kCATransitionFade;
animation.duration = 0.6;
[animation setTimingFunction:[CAMediaTimingFunction
functionWithName:kCAMediaTimingFunctionDefault]];
[self.contentView.layer addAnimation:animation forKey:@"deselectRow"];
[CATransaction commit];
}
}
- (UIImage *)imageByApplyingAlpha:(UIImage *)image withAlpha:(CGFloat) alpha {
UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0f);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGRect area = CGRectMake(0, 0, image.size.width, image.size.height);
CGContextScaleCTM(ctx, 1, -1);
CGContextTranslateCTM(ctx, 0, -area.size.height);
CGContextSetBlendMode(ctx, kCGBlendModeMultiply);
CGContextSetAlpha(ctx, alpha);
CGContextDrawImage(ctx, area, image.CGImage);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
@end

View file

@ -75,6 +75,7 @@
MoveSiteViewController *moveSiteViewController; MoveSiteViewController *moveSiteViewController;
TrainerViewController *trainerViewController; TrainerViewController *trainerViewController;
OriginalStoryViewController *originalStoryViewController; OriginalStoryViewController *originalStoryViewController;
UINavigationController *originalStoryViewNavController;
UserProfileViewController *userProfileViewController; UserProfileViewController *userProfileViewController;
IASKAppSettingsViewController *preferencesViewController; IASKAppSettingsViewController *preferencesViewController;
@ -155,6 +156,7 @@
@property (nonatomic) UINavigationController *shareNavigationController; @property (nonatomic) UINavigationController *shareNavigationController;
@property (nonatomic) UINavigationController *trainNavigationController; @property (nonatomic) UINavigationController *trainNavigationController;
@property (nonatomic) UINavigationController *userProfileNavigationController; @property (nonatomic) UINavigationController *userProfileNavigationController;
@property (nonatomic) UINavigationController *originalStoryViewNavController;
@property (nonatomic) IBOutlet NBContainerViewController *masterContainerViewController; @property (nonatomic) IBOutlet NBContainerViewController *masterContainerViewController;
@property (nonatomic) IBOutlet DashboardViewController *dashboardViewController; @property (nonatomic) IBOutlet DashboardViewController *dashboardViewController;
@property (nonatomic) IBOutlet NewsBlurViewController *feedsViewController; @property (nonatomic) IBOutlet NewsBlurViewController *feedsViewController;
@ -258,7 +260,7 @@
- (void)setupReachability; - (void)setupReachability;
// social // social
- (NSDictionary *)getUser:(int)userId; - (NSDictionary *)getUser:(NSInteger)userId;
- (void)showUserProfileModal:(id)sender; - (void)showUserProfileModal:(id)sender;
- (void)pushUserProfile; - (void)pushUserProfile;
- (void)hideUserProfileModal; - (void)hideUserProfileModal;
@ -267,6 +269,7 @@
- (void)showMoveSite; - (void)showMoveSite;
- (void)openTrainSite; - (void)openTrainSite;
- (void)openTrainSiteWithFeedLoaded:(BOOL)feedLoaded from:(id)sender;
- (void)openTrainStory:(id)sender; - (void)openTrainStory:(id)sender;
- (void)loadFeedDetailView; - (void)loadFeedDetailView;
- (void)loadTryFeedDetailView:(NSString *)feedId withStory:(NSString *)contentId isSocial:(BOOL)social withUser:(NSDictionary *)user showFindingStory:(BOOL)showHUD; - (void)loadTryFeedDetailView:(NSString *)feedId withStory:(NSString *)contentId isSocial:(BOOL)social withUser:(NSDictionary *)user showFindingStory:(BOOL)showHUD;
@ -294,17 +297,18 @@
- (void)showConnectToService:(NSString *)serviceName; - (void)showConnectToService:(NSString *)serviceName;
- (void)refreshUserProfile:(void(^)())callback; - (void)refreshUserProfile:(void(^)())callback;
- (int)indexOfNextUnreadStory; - (BOOL)isStoryUnread:(NSDictionary *)story;
- (int)locationOfNextUnreadStory; - (NSInteger)indexOfNextUnreadStory;
- (int)indexOfNextStory; - (NSInteger)locationOfNextUnreadStory;
- (int)locationOfNextStory; - (NSInteger)indexOfNextStory;
- (int)indexOfActiveStory; - (NSInteger)locationOfNextStory;
- (int)indexOfStoryId:(id)storyId; - (NSInteger)indexOfActiveStory;
- (int)locationOfActiveStory; - (NSInteger)indexOfStoryId:(id)storyId;
- (int)indexFromLocation:(int)location; - (NSInteger)locationOfActiveStory;
- (NSInteger)indexFromLocation:(NSInteger)location;
- (void)pushReadStory:(id)storyId; - (void)pushReadStory:(id)storyId;
- (id)popReadStory; - (id)popReadStory;
- (int)locationOfStoryId:(id)storyId; - (NSInteger)locationOfStoryId:(id)storyId;
- (NSString *)activeOrder; - (NSString *)activeOrder;
- (NSString *)activeReadFilter; - (NSString *)activeReadFilter;
@ -314,10 +318,10 @@
- (void)addFeedUserProfiles:(NSArray *)activeFeedUserProfilesValue; - (void)addFeedUserProfiles:(NSArray *)activeFeedUserProfilesValue;
- (void)populateDictUnreadCounts; - (void)populateDictUnreadCounts;
- (int)unreadCount; - (NSInteger)unreadCount;
- (int)allUnreadCount; - (NSInteger)allUnreadCount;
- (int)unreadCountForFeed:(NSString *)feedId; - (NSInteger)unreadCountForFeed:(NSString *)feedId;
- (int)unreadCountForFolder:(NSString *)folderName; - (NSInteger)unreadCountForFolder:(NSString *)folderName;
- (UnreadCounts *)splitUnreadCountForFeed:(NSString *)feedId; - (UnreadCounts *)splitUnreadCountForFeed:(NSString *)feedId;
- (UnreadCounts *)splitUnreadCountForFolder:(NSString *)folderName; - (UnreadCounts *)splitUnreadCountForFolder:(NSString *)folderName;
- (void)markActiveStoryRead; - (void)markActiveStoryRead;
@ -327,12 +331,19 @@
- (void)markStoryRead:(NSDictionary *)story feed:(NSDictionary *)feed; - (void)markStoryRead:(NSDictionary *)story feed:(NSDictionary *)feed;
- (void)markStoryUnread:(NSString *)storyId feedId:(id)feedId; - (void)markStoryUnread:(NSString *)storyId feedId:(id)feedId;
- (void)markStoryUnread:(NSDictionary *)story feed:(NSDictionary *)feed; - (void)markStoryUnread:(NSDictionary *)story feed:(NSDictionary *)feed;
- (void)markActiveStorySaved:(BOOL)saved;
- (void)markActiveFeedAllRead;
- (void)markActiveFolderAllRead; - (void)markActiveFolderAllRead;
- (void)markFeedAllRead:(id)feedId; - (void)markFeedAllRead:(id)feedId;
- (void)markFeedReadInCache:(NSArray *)feedIds;
- (void)markFeedReadInCache:(NSArray *)feedIds cutoffTimestamp:(NSInteger)cutoff;
- (void)markStoriesRead:(NSDictionary *)stories inFeeds:(NSArray *)feeds cutoffTimestamp:(NSInteger)cutoff;
- (void)requestFailedMarkStoryRead:(ASIFormDataRequest *)request;
- (void)finishMarkAllAsRead:(ASIHTTPRequest *)request;
- (void)markStory:story asSaved:(BOOL)saved;
- (void)calculateStoryLocations; - (void)calculateStoryLocations;
+ (int)computeStoryScore:(NSDictionary *)intelligence; + (NSInteger)computeStoryScore:(NSDictionary *)intelligence;
- (NSString *)extractFolderName:(NSString *)folderName; - (NSString *)extractFolderName:(NSString *)folderName;
- (NSString *)extractParentFolderName:(NSString *)folderName; - (NSString *)extractParentFolderName:(NSString *)folderName;
- (NSDictionary *)getFeed:(NSString *)feedId; - (NSDictionary *)getFeed:(NSString *)feedId;
@ -341,15 +352,14 @@
+ (UIView *)makeGradientView:(CGRect)rect startColor:(NSString *)start endColor:(NSString *)end; + (UIView *)makeGradientView:(CGRect)rect startColor:(NSString *)start endColor:(NSString *)end;
- (UIView *)makeFeedTitleGradient:(NSDictionary *)feed withRect:(CGRect)rect; - (UIView *)makeFeedTitleGradient:(NSDictionary *)feed withRect:(CGRect)rect;
- (UIView *)makeFeedTitle:(NSDictionary *)feed; - (UIView *)makeFeedTitle:(NSDictionary *)feed;
- (UIButton *)makeRightFeedTitle:(NSDictionary *)feed;
- (void)toggleAuthorClassifier:(NSString *)author feedId:(NSString *)feedId; - (void)toggleAuthorClassifier:(NSString *)author feedId:(NSString *)feedId;
- (void)toggleTagClassifier:(NSString *)tag feedId:(NSString *)feedId; - (void)toggleTagClassifier:(NSString *)tag feedId:(NSString *)feedId;
- (void)toggleTitleClassifier:(NSString *)title feedId:(NSString *)feedId score:(int)score; - (void)toggleTitleClassifier:(NSString *)title feedId:(NSString *)feedId score:(NSInteger)score;
- (void)toggleFeedClassifier:(NSString *)feedId; - (void)toggleFeedClassifier:(NSString *)feedId;
- (void)requestClassifierResponse:(ASIHTTPRequest *)request withFeed:(NSString *)feedId; - (void)requestClassifierResponse:(ASIHTTPRequest *)request withFeed:(NSString *)feedId;
- (int)databaseSchemaVersion:(FMDatabase *)db; - (NSInteger)databaseSchemaVersion:(FMDatabase *)db;
- (void)createDatabaseConnection; - (void)createDatabaseConnection;
- (void)setupDatabase:(FMDatabase *)db; - (void)setupDatabase:(FMDatabase *)db;
- (void)cancelOfflineQueue; - (void)cancelOfflineQueue;
@ -359,9 +369,11 @@
- (BOOL)isReachabileForOffline; - (BOOL)isReachabileForOffline;
- (void)storeUserProfiles:(NSArray *)userProfiles; - (void)storeUserProfiles:(NSArray *)userProfiles;
- (void)queueReadStories:(NSDictionary *)feedsStories; - (void)queueReadStories:(NSDictionary *)feedsStories;
- (BOOL)dequeueReadStoryHash:(NSString *)storyHash inFeed:(NSString *)storyFeedId;
- (void)flushQueuedReadStories:(BOOL)forceCheck withCallback:(void(^)())callback; - (void)flushQueuedReadStories:(BOOL)forceCheck withCallback:(void(^)())callback;
- (void)syncQueuedReadStories:(FMDatabase *)db withStories:(NSDictionary *)hashes withCallback:(void(^)())callback; - (void)syncQueuedReadStories:(FMDatabase *)db withStories:(NSDictionary *)hashes withCallback:(void(^)())callback;
- (void)prepareActiveCachedImages:(FMDatabase *)db; - (void)prepareActiveCachedImages:(FMDatabase *)db;
- (void)cleanImageCache;
- (void)deleteAllCachedImages; - (void)deleteAllCachedImages;
@end @end

File diff suppressed because it is too large Load diff

View file

@ -15,16 +15,20 @@
#import "WEPopoverController.h" #import "WEPopoverController.h"
#import "NBNotifier.h" #import "NBNotifier.h"
#import "IASKAppSettingsViewController.h" #import "IASKAppSettingsViewController.h"
#import "MCSwipeTableViewCell.h"
@class NewsBlurAppDelegate; @class NewsBlurAppDelegate;
@interface NewsBlurViewController : BaseViewController @interface NewsBlurViewController : BaseViewController
<UITableViewDelegate, UITableViewDataSource, <UITableViewDelegate, UITableViewDataSource,
UIAlertViewDelegate, PullToRefreshViewDelegate, UIAlertViewDelegate, PullToRefreshViewDelegate,
ASIHTTPRequestDelegate, NSCacheDelegate, ASIHTTPRequestDelegate, NSCacheDelegate,
WEPopoverControllerDelegate, WEPopoverControllerDelegate,
UIPopoverControllerDelegate, UIPopoverControllerDelegate,
IASKSettingsDelegate> { IASKSettingsDelegate,
MCSwipeTableViewCellDelegate,
UIGestureRecognizerDelegate,
UIActionSheetDelegate> {
NewsBlurAppDelegate *appDelegate; NewsBlurAppDelegate *appDelegate;
NSMutableDictionary * activeFeedLocations; NSMutableDictionary * activeFeedLocations;
@ -60,6 +64,12 @@ IASKSettingsDelegate> {
@property (nonatomic) IBOutlet UIBarButtonItem * addBarButton; @property (nonatomic) IBOutlet UIBarButtonItem * addBarButton;
@property (nonatomic) IBOutlet UIBarButtonItem * settingsBarButton; @property (nonatomic) IBOutlet UIBarButtonItem * settingsBarButton;
@property (nonatomic) IBOutlet UIBarButtonItem * activitiesButton; @property (nonatomic) IBOutlet UIBarButtonItem * activitiesButton;
@property (nonatomic) IBOutlet UIBarButtonItem *userInfoBarButton;
@property (nonatomic) IBOutlet UIBarButtonItem *userAvatarButton;
@property (nonatomic) IBOutlet UILabel *neutralCount;
@property (nonatomic) IBOutlet UILabel *positiveCount;
@property (nonatomic) IBOutlet UILabel *userLabel;
@property (nonatomic) IBOutlet UIImageView *greenIcon;
@property (nonatomic) NSMutableDictionary *activeFeedLocations; @property (nonatomic) NSMutableDictionary *activeFeedLocations;
@property (nonatomic) NSMutableDictionary *stillVisibleFeeds; @property (nonatomic) NSMutableDictionary *stillVisibleFeeds;
@property (nonatomic) NSMutableDictionary *visibleFolders; @property (nonatomic) NSMutableDictionary *visibleFolders;
@ -71,6 +81,7 @@ IASKSettingsDelegate> {
@property (nonatomic) IBOutlet UISegmentedControl * intelligenceControl; @property (nonatomic) IBOutlet UISegmentedControl * intelligenceControl;
@property (nonatomic, retain) WEPopoverController *popoverController; @property (nonatomic, retain) WEPopoverController *popoverController;
@property (nonatomic) NSIndexPath *currentRowAtIndexPath; @property (nonatomic) NSIndexPath *currentRowAtIndexPath;
@property (nonatomic) NSInteger currentSection;
@property (strong, nonatomic) IBOutlet UIView *noFocusMessage; @property (strong, nonatomic) IBOutlet UIView *noFocusMessage;
@property (strong, nonatomic) IBOutlet UIBarButtonItem *toolbarLeftMargin; @property (strong, nonatomic) IBOutlet UIBarButtonItem *toolbarLeftMargin;
@property (nonatomic, retain) NBNotifier *notifier; @property (nonatomic, retain) NBNotifier *notifier;
@ -82,9 +93,12 @@ IASKSettingsDelegate> {
- (void)finishLoadingFeedList:(ASIHTTPRequest *)request; - (void)finishLoadingFeedList:(ASIHTTPRequest *)request;
- (void)finishLoadingFeedListWithDict:(NSDictionary *)results; - (void)finishLoadingFeedListWithDict:(NSDictionary *)results;
- (void)finishRefreshingFeedList:(ASIHTTPRequest *)request; - (void)finishRefreshingFeedList:(ASIHTTPRequest *)request;
- (void)setUserAvatarLayout:(UIInterfaceOrientation)orientation;
- (void)didSelectSectionHeader:(UIButton *)button; - (void)didSelectSectionHeader:(UIButton *)button;
- (IBAction)selectIntelligence; - (IBAction)selectIntelligence;
- (void)markFeedRead:(NSString *)feedId cutoffDays:(NSInteger)days;
- (void)markFeedsRead:(NSArray *)feedIds cutoffDays:(NSInteger)days;
- (void)requestFailedMarkStoryRead:(ASIFormDataRequest *)request;
- (void)finishMarkAllAsRead:(ASIHTTPRequest *)request;
- (void)didCollapseFolder:(UIButton *)button; - (void)didCollapseFolder:(UIButton *)button;
- (BOOL)isFeedVisible:(id)feedId; - (BOOL)isFeedVisible:(id)feedId;
- (void)changeToAllMode; - (void)changeToAllMode;
@ -102,7 +116,7 @@ IASKSettingsDelegate> {
- (void)refreshFeedList; - (void)refreshFeedList;
- (void)refreshFeedList:(id)feedId; - (void)refreshFeedList:(id)feedId;
- (void)pullToRefreshViewShouldRefresh:(PullToRefreshView *)view; - (void)pullToRefreshViewShouldRefresh:(PullToRefreshView *)view;
- (void)loadOfflineFeeds; - (void)loadOfflineFeeds:(BOOL)failed;
- (void)showUserProfile; - (void)showUserProfile;
- (IBAction)showSettingsPopover:(id)sender; - (IBAction)showSettingsPopover:(id)sender;
- (IBAction)showInteractionsPopover:(id)sender; - (IBAction)showInteractionsPopover:(id)sender;
@ -111,8 +125,8 @@ IASKSettingsDelegate> {
- (IBAction)tapAddSite:(id)sender; - (IBAction)tapAddSite:(id)sender;
- (void)resetToolbar; - (void)resetToolbar;
- (void)layoutHeaderCounts:(UIInterfaceOrientation)orientation;
- (void)refreshHeaderCounts; - (void)refreshHeaderCounts;
- (void)refreshHeaderCounts:(UIInterfaceOrientation)orientation;
- (void)settingsViewControllerDidEnd:(IASKAppSettingsViewController*)sender; - (void)settingsViewControllerDidEnd:(IASKAppSettingsViewController*)sender;
- (void)settingDidChange:(NSNotification*)notification; - (void)settingDidChange:(NSNotification*)notification;

File diff suppressed because it is too large Load diff

View file

@ -11,13 +11,13 @@
@class NewsBlurAppDelegate; @class NewsBlurAppDelegate;
static const CGFloat kNavBarHeight = 58.0f; static const CGFloat kNavBarHeight = 78.0f;
static const CGFloat kLabelHeight = 18.0f; static const CGFloat kLabelHeight = 18.0f;
static const CGFloat kMargin = 6.0f; static const CGFloat kMargin = 6.0f;
static const CGFloat kSpacer = 2.0f; static const CGFloat kSpacer = 2.0f;
static const CGFloat kLabelFontSize = 12.0f; static const CGFloat kLabelFontSize = 12.0f;
static const CGFloat kAddressHeight = 30.0f; static const CGFloat kAddressHeight = 30.0f;
static const CGFloat kButtonWidth = 48.0f; static const CGFloat kButtonWidth = 68.0f;
@interface OriginalStoryViewController : BaseViewController @interface OriginalStoryViewController : BaseViewController
<UIActionSheetDelegate, UITextFieldDelegate, UIWebViewDelegate> { <UIActionSheetDelegate, UITextFieldDelegate, UIWebViewDelegate> {
@ -37,6 +37,7 @@ static const CGFloat kButtonWidth = 48.0f;
} }
@property (nonatomic) IBOutlet NewsBlurAppDelegate *appDelegate; @property (nonatomic) IBOutlet NewsBlurAppDelegate *appDelegate;
@property (nonatomic) IBOutlet UINavigationBar *navBar;
@property (nonatomic) IBOutlet UIBarButtonItem *closeButton; @property (nonatomic) IBOutlet UIBarButtonItem *closeButton;
@property (nonatomic) IBOutlet UIWebView *webView; @property (nonatomic) IBOutlet UIWebView *webView;
@property (nonatomic) IBOutlet UIBarButtonItem* back; @property (nonatomic) IBOutlet UIBarButtonItem* back;
@ -47,6 +48,7 @@ static const CGFloat kButtonWidth = 48.0f;
@property (nonatomic) IBOutlet UITextField *pageUrl; @property (nonatomic) IBOutlet UITextField *pageUrl;
@property (nonatomic) IBOutlet UIToolbar *toolbar; @property (nonatomic) IBOutlet UIToolbar *toolbar;
- (void)layoutNavBar;
- (void)layoutForInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; - (void)layoutForInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;
- (IBAction) doCloseOriginalStoryViewController; - (IBAction) doCloseOriginalStoryViewController;
- (IBAction) doOpenActionSheet:(id)sender; - (IBAction) doOpenActionSheet:(id)sender;

View file

@ -14,6 +14,7 @@
#import "MBProgressHUD.h" #import "MBProgressHUD.h"
#import "UIBarButtonItem+Image.h" #import "UIBarButtonItem+Image.h"
#import "UIActivitiesControl.h" #import "UIActivitiesControl.h"
#import "NBBarButtonItem.h"
@implementation OriginalStoryViewController @implementation OriginalStoryViewController
@ -27,6 +28,7 @@
@synthesize pageTitle; @synthesize pageTitle;
@synthesize pageUrl; @synthesize pageUrl;
@synthesize toolbar; @synthesize toolbar;
@synthesize navBar;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
@ -37,6 +39,7 @@
- (void)viewWillAppear:(BOOL)animated { - (void)viewWillAppear:(BOOL)animated {
// NSLog(@"Original Story View: %@", [appDelegate activeOriginalStoryURL]); // NSLog(@"Original Story View: %@", [appDelegate activeOriginalStoryURL]);
appDelegate.originalStoryViewNavController.navigationBar.hidden = YES;
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:appDelegate.activeOriginalStoryURL] ; NSURLRequest *request = [[NSURLRequest alloc] initWithURL:appDelegate.activeOriginalStoryURL] ;
[self updateAddress:request]; [self updateAddress:request];
@ -51,6 +54,10 @@
[HUD hide:YES afterDelay:2]; [HUD hide:YES afterDelay:2];
} }
- (void)viewDidAppear:(BOOL)animated {
[self layoutNavBar];
}
- (void)viewWillDisappear:(BOOL)animated { - (void)viewWillDisappear:(BOOL)animated {
if ([self.webView isLoading]) { if ([self.webView isLoading]) {
[self.webView stopLoading]; [self.webView stopLoading];
@ -65,19 +72,11 @@
[self layoutForInterfaceOrientation:toInterfaceOrientation]; [self layoutForInterfaceOrientation:toInterfaceOrientation];
} }
- (void)viewDidLoad { - (void)viewDidLoad {
CGRect navBarFrame = self.view.bounds; CGRect labelFrame = CGRectMake(kMargin, kSpacer + 20,
navBarFrame.size.height = kNavBarHeight; navBar.bounds.size.width - 2*kMargin,
UINavigationBar *navBar = [[UINavigationBar alloc] initWithFrame:navBarFrame];
navBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
toolbar.autoresizingMask = toolbar.autoresizingMask | UIViewAutoresizingFlexibleHeight | UIViewContentModeBottom;
[navBar
setBackgroundImage:[UIImage imageNamed:@"toolbar_tall_background.png"]
forBarMetrics:UIBarMetricsDefault];
CGRect labelFrame = CGRectMake(kMargin, kSpacer,
navBar.bounds.size.width - 2*kMargin,
kLabelHeight); kLabelHeight);
UILabel *label = [[UILabel alloc] initWithFrame:labelFrame]; UILabel *label = [[UILabel alloc] initWithFrame:labelFrame];
label.autoresizingMask = UIViewAutoresizingFlexibleWidth; label.autoresizingMask = UIViewAutoresizingFlexibleWidth;
label.backgroundColor = [UIColor clearColor]; label.backgroundColor = [UIColor clearColor];
@ -90,29 +89,28 @@
[navBar addSubview:label]; [navBar addSubview:label];
self.pageTitle = label; self.pageTitle = label;
UIBarButtonItem *close = [[UIBarButtonItem alloc]
UIBarButtonItem *close = [[UIBarButtonItem alloc] initWithTitle:@"Close"
initWithTitle:@"Close" style:UIBarButtonItemStyleBordered
style:UIBarButtonItemStyleBordered target:self
target:self
action:@selector(doCloseOriginalStoryViewController)]; action:@selector(doCloseOriginalStoryViewController)];
close.width = kButtonWidth; close.width = kButtonWidth;
CGRect closeButtonFrame = CGRectMake(0, CGRect closeButtonFrame = CGRectMake(-20,
kSpacer*2.0 + kLabelHeight - 7.0f, kSpacer*2.0 + kLabelHeight - 7.0f + 20,
kButtonWidth + kMargin, kButtonWidth + kMargin,
44.0); 44.0);
TransparentToolbar* tools = [[TransparentToolbar alloc] TransparentToolbar* tools = [[TransparentToolbar alloc]
initWithFrame:closeButtonFrame]; initWithFrame:closeButtonFrame];
[tools setItems:[NSArray arrayWithObject:close] animated:NO]; [tools setItems:[NSArray arrayWithObject:close] animated:NO];
[tools setTintColor:UIColorFromRGB(0x183353)]; [tools setTintColor:UIColorFromRGB(0x183353)];
[navBar addSubview:tools]; [navBar addSubview:tools];
CGRect addressFrame = CGRectMake(closeButtonFrame.origin.x + CGRect addressFrame = CGRectMake(closeButtonFrame.origin.x +
closeButtonFrame.size.width + closeButtonFrame.size.width +
kMargin, kMargin,
kSpacer*2.0 + kLabelHeight, kSpacer*2.0 + kLabelHeight + 20,
labelFrame.size.width labelFrame.size.width
- kButtonWidth - kMargin*2, - kButtonWidth - kMargin*2 + 20,
kAddressHeight); kAddressHeight);
UITextField *address = [[UITextField alloc] initWithFrame:addressFrame]; UITextField *address = [[UITextField alloc] initWithFrame:addressFrame];
address.autoresizingMask = UIViewAutoresizingFlexibleWidth; address.autoresizingMask = UIViewAutoresizingFlexibleWidth;
@ -128,43 +126,43 @@
address.delegate = self; address.delegate = self;
[navBar addSubview:address]; [navBar addSubview:address];
self.pageUrl = address; self.pageUrl = address;
[self.view addSubview:navBar];
UIImage *backImage = [UIImage imageNamed:@"barbutton_back.png"]; UIImage *backImage = [UIImage imageNamed:@"barbutton_back.png"];
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom]; NBBarButtonItem *backButton = [NBBarButtonItem buttonWithType:UIButtonTypeCustom];
backButton.bounds = CGRectMake(0, 0, 44, 44); backButton.bounds = CGRectMake(0, 0, 44, 44);
[backButton setImage:backImage forState:UIControlStateNormal]; [backButton setImage:backImage forState:UIControlStateNormal];
[backButton addTarget:self action:@selector(webViewGoBack:) forControlEvents:UIControlEventTouchUpInside]; [backButton addTarget:self action:@selector(webViewGoBack:) forControlEvents:UIControlEventTouchUpInside];
[back setCustomView:backButton]; [back setCustomView:backButton];
UIImage *forwardImage = [UIImage imageNamed:@"barbutton_forward.png"]; UIImage *forwardImage = [UIImage imageNamed:@"barbutton_forward.png"];
UIButton *forwardButton = [UIButton buttonWithType:UIButtonTypeCustom]; NBBarButtonItem *forwardButton = [NBBarButtonItem buttonWithType:UIButtonTypeCustom];
forwardButton.bounds = CGRectMake(0, 0, 44, 44); forwardButton.bounds = CGRectMake(0, 0, 44, 44);
[forwardButton setImage:forwardImage forState:UIControlStateNormal]; [forwardButton setImage:forwardImage forState:UIControlStateNormal];
[forwardButton addTarget:self action:@selector(webViewGoForward:) forControlEvents:UIControlEventTouchUpInside]; [forwardButton addTarget:self action:@selector(webViewGoForward:) forControlEvents:UIControlEventTouchUpInside];
[forward setCustomView:forwardButton]; [forward setCustomView:forwardButton];
UIImage *refreshImage = [UIImage imageNamed:@"barbutton_refresh.png"]; UIImage *refreshImage = [UIImage imageNamed:@"barbutton_refresh.png"];
UIButton *refreshButton = [UIButton buttonWithType:UIButtonTypeCustom]; NBBarButtonItem *refreshButton = [NBBarButtonItem buttonWithType:UIButtonTypeCustom];
refreshButton.bounds = CGRectMake(0, 0, 44, 44); refreshButton.bounds = CGRectMake(0, 0, 44, 44);
[refreshButton setImage:refreshImage forState:UIControlStateNormal]; [refreshButton setImage:refreshImage forState:UIControlStateNormal];
[refreshButton addTarget:self action:@selector(webViewRefresh:) forControlEvents:UIControlEventTouchUpInside]; [refreshButton addTarget:self action:@selector(webViewRefresh:) forControlEvents:UIControlEventTouchUpInside];
[refresh setCustomView:refreshButton]; [refresh setCustomView:refreshButton];
UIImage *sendtoImage = [UIImage imageNamed:@"barbutton_sendto.png"]; UIImage *sendtoImage = [UIImage imageNamed:@"barbutton_sendto.png"];
UIButton *sendtoButton = [UIButton buttonWithType:UIButtonTypeCustom]; NBBarButtonItem *sendtoButton = [NBBarButtonItem buttonWithType:UIButtonTypeCustom];
sendtoButton.bounds = CGRectMake(0, 0, 44, 44); sendtoButton.bounds = CGRectMake(0, 0, 44, 44);
[sendtoButton setImage:sendtoImage forState:UIControlStateNormal]; [sendtoButton setImage:sendtoImage forState:UIControlStateNormal];
[sendtoButton addTarget:self action:@selector(doOpenActionSheet:) forControlEvents:UIControlEventTouchUpInside]; [sendtoButton addTarget:self action:@selector(doOpenActionSheet:) forControlEvents:UIControlEventTouchUpInside];
[pageAction setCustomView:sendtoButton]; [pageAction setCustomView:sendtoButton];
}
CGRect webViewFrame = CGRectMake(0,
navBarFrame.origin.y + - (void)layoutNavBar {
navBarFrame.size.height, CGRect navBarFrame = self.view.bounds;
self.view.frame.size.width, navBarFrame.size.height = kNavBarHeight;
self.view.frame.size.height - kNavBarHeight - 44); navBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
self.webView.frame = webViewFrame; navBar.frame = navBarFrame;
navBar.translucent = NO;
toolbar.translucent = NO;
} }
- (IBAction)webViewGoBack:(id)sender { - (IBAction)webViewGoBack:(id)sender {
@ -180,6 +178,8 @@
} }
- (void) layoutForInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { - (void) layoutForInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
[self layoutNavBar];
CGSize toolbarSize = [self.toolbar sizeThatFits:self.view.bounds.size]; CGSize toolbarSize = [self.toolbar sizeThatFits:self.view.bounds.size];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
self.toolbar.frame = CGRectMake(-10.0f, self.toolbar.frame = CGRectMake(-10.0f,

View file

@ -181,10 +181,14 @@
// Calculate the expected size based on the font and linebreak mode of your label // Calculate the expected size based on the font and linebreak mode of your label
CGSize maximumLabelSize = CGSizeMake(width - kTopBadgeTextXCoordinate - 10, 60); CGSize maximumLabelSize = CGSizeMake(width - kTopBadgeTextXCoordinate - 10, 60);
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle defaultParagraphStyle] mutableCopy];
paragraphStyle.lineBreakMode = bio.lineBreakMode;
CGSize expectedLabelSize = [bio.text CGSize expectedLabelSize = [bio.text
sizeWithFont:bio.font boundingRectWithSize:maximumLabelSize
constrainedToSize:maximumLabelSize options:nil
lineBreakMode:bio.lineBreakMode]; attributes:@{NSFontAttributeName: bio.font,
NSParagraphStyleAttributeName: paragraphStyle}
context:nil].size;
CGRect newFrame = bio.frame; CGRect newFrame = bio.frame;
newFrame.size.height = expectedLabelSize.height; newFrame.size.height = expectedLabelSize.height;
bio.frame = newFrame; bio.frame = newFrame;

View file

@ -23,6 +23,7 @@
@property (nonatomic) IBOutlet UILabel *storyTitle; @property (nonatomic) IBOutlet UILabel *storyTitle;
@property (nonatomic) NSString * activeReplyId; @property (nonatomic) NSString * activeReplyId;
@property (nonatomic) NSString * activeCommentId; @property (nonatomic) NSString * activeCommentId;
@property (nonatomic) NSString * activeStoryId;
@property (nonatomic) NSString* currentType; @property (nonatomic) NSString* currentType;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *keyboardHeight; @property (weak, nonatomic) IBOutlet NSLayoutConstraint *keyboardHeight;

View file

@ -26,6 +26,7 @@
@synthesize appDelegate; @synthesize appDelegate;
@synthesize activeReplyId; @synthesize activeReplyId;
@synthesize activeCommentId; @synthesize activeCommentId;
@synthesize activeStoryId;
@synthesize currentType; @synthesize currentType;
@synthesize storyTitle; @synthesize storyTitle;
@ -178,6 +179,8 @@
self.twitterButton.frame = CGRectMake(v.width - 20 - bW*3 - bP*2, o.y + c.height + bP, bW, bH); self.twitterButton.frame = CGRectMake(v.width - 20 - bW*3 - bP*2, o.y + c.height + bP, bW, bH);
self.facebookButton.frame = CGRectMake(v.width - 20 - bW*2 - bP*1, o.y + c.height + bP, bW, bH); self.facebookButton.frame = CGRectMake(v.width - 20 - bW*2 - bP*1, o.y + c.height + bP, bW, bH);
self.appdotnetButton.frame = CGRectMake(v.width - 20 - bW*1 - bP*0, o.y + c.height + bP, bW, bH); self.appdotnetButton.frame = CGRectMake(v.width - 20 - bW*1 - bP*0, o.y + c.height + bP, bW, bH);
[self onTextChange:nil];
} }
- (IBAction)doCancelButton:(id)sender { - (IBAction)doCancelButton:(id)sender {
@ -270,8 +273,10 @@
// Don't bother to reset comment field for replies while on the same story. // Don't bother to reset comment field for replies while on the same story.
// It'll get cleared out on a new story and when posting a reply. // It'll get cleared out on a new story and when posting a reply.
if (!self.activeCommentId || ![self.activeCommentId isEqualToString:userId]) { if (!self.activeCommentId || ![self.activeCommentId isEqualToString:userId] ||
!self.activeStoryId || ![self.activeStoryId isEqualToString:[appDelegate.activeStory objectForKey:@"id"]]) {
self.activeCommentId = userId; self.activeCommentId = userId;
self.activeStoryId = [appDelegate.activeStory objectForKey:@"id"];
self.commentField.text = @""; self.commentField.text = @"";
} }
} else if ([type isEqualToString: @"edit-share"]) { } else if ([type isEqualToString: @"edit-share"]) {
@ -282,7 +287,7 @@
// get old comment // get old comment
self.commentField.text = [self stringByStrippingHTML:[appDelegate.activeComment objectForKey:@"comments"]]; self.commentField.text = [self stringByStrippingHTML:[appDelegate.activeComment objectForKey:@"comments"]];
[submitButton setTitle:@"Save your comments"]; [submitButton setTitle:@"Share with comments"];
[submitButton setAction:(@selector(doShareThisStory:))]; [submitButton setAction:(@selector(doShareThisStory:))];
} else if ([type isEqualToString: @"share"]) { } else if ([type isEqualToString: @"share"]) {
facebookButton.hidden = NO; facebookButton.hidden = NO;
@ -333,9 +338,10 @@
} }
if (appDelegate.isSocialRiverView) { if (appDelegate.isSocialRiverView) {
if ([appDelegate.activeStory objectForKey:@"friend_user_ids"] != nil) { if ([[appDelegate.activeStory objectForKey:@"friend_user_ids"] count] > 0) {
NSString *sourceUserIdStr = [NSString stringWithFormat:@"%@", [[appDelegate.activeStory objectForKey:@"friend_user_ids"] objectAtIndex:0]]; [request setPostValue:[NSString stringWithFormat:@"%@", [appDelegate.activeStory objectForKey:@"friend_user_ids"][0]] forKey:@"source_user_id"];
[request setPostValue:sourceUserIdStr forKey:@"source_user_id"]; } else if ([[appDelegate.activeStory objectForKey:@"public_user_ids"] count] > 0) {
[request setPostValue:[NSString stringWithFormat:@"%@", [appDelegate.activeStory objectForKey:@"public_user_ids"][0]] forKey:@"source_user_id"];
} }
} else { } else {
if ([appDelegate.activeStory objectForKey:@"social_user_id"] != nil) { if ([appDelegate.activeStory objectForKey:@"social_user_id"] != nil) {
@ -373,8 +379,8 @@
appDelegate.activeFeedUserProfiles = [DataUtilities appDelegate.activeFeedUserProfiles = [DataUtilities
updateUserProfiles:appDelegate.activeFeedUserProfiles updateUserProfiles:appDelegate.activeFeedUserProfiles
withNewUserProfiles:userProfiles]; withNewUserProfiles:userProfiles];
[appDelegate.feedDetailViewController redrawUnreadStory];
[self replaceStory:[results objectForKey:@"story"] withReplyId:nil]; [self replaceStory:[results objectForKey:@"story"] withReplyId:nil];
[appDelegate.feedDetailViewController redrawUnreadStory];
} }
# pragma mark # pragma mark
@ -483,8 +489,8 @@
-(void)onTextChange:(NSNotification*)notification { -(void)onTextChange:(NSNotification*)notification {
NSString *text = self.commentField.text; NSString *text = self.commentField.text;
if ([self.submitButton.title isEqualToString:@"Share this story"] || if ([self.currentType isEqualToString: @"share"] ||
[self.submitButton.title isEqualToString:@"Share with comments"]) { [self.currentType isEqualToString:@"edit-share"]) {
if (text.length) { if (text.length) {
self.submitButton.title = @"Share with comments"; self.submitButton.title = @"Share with comments";
} else { } else {

View file

@ -1,365 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<archive type="com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB" version="8.00"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB" version="3.0" toolsVersion="4510" systemVersion="12F37" targetRuntime="iOS.CocoaTouch.iPad" propertyAccessControl="none">
<data> <dependencies>
<int key="IBDocument.SystemTarget">1552</int> <deployment defaultVersion="1792" identifier="iOS"/>
<string key="IBDocument.SystemVersion">12C3006</string> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3742"/>
<string key="IBDocument.InterfaceBuilderVersion">3084</string> </dependencies>
<string key="IBDocument.AppKitVersion">1187.34</string> <objects>
<string key="IBDocument.HIToolboxVersion">625.00</string> <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="ShareViewController">
<object class="NSMutableDictionary" key="IBDocument.PluginVersions"> <connections>
<string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> <outlet property="appdotnetButton" destination="52" id="56"/>
<string key="NS.object.0">2083</string> <outlet property="commentField" destination="19" id="29"/>
</object> <outlet property="facebookButton" destination="53" id="55"/>
<array key="IBDocument.IntegratedClassDependencies"> <outlet property="twitterButton" destination="51" id="54"/>
<string>IBProxyObject</string> <outlet property="view" destination="2" id="3"/>
<string>IBUIButton</string> </connections>
<string>IBUITextView</string> </placeholder>
<string>IBUIView</string> <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
</array> <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="2">
<array key="IBDocument.PluginDependencies"> <rect key="frame" x="0.0" y="0.0" width="704" height="100"/>
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
</array> <subviews>
<object class="NSMutableDictionary" key="IBDocument.Metadata"> <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" id="19">
<string key="NS.key.0">PluginDependencyRecalculationVersion</string> <rect key="frame" x="20" y="15" width="664" height="39"/>
<integer value="1" key="NS.object.0"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
</object> <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<array class="NSMutableArray" key="IBDocument.RootObjects" id="1000"> <fontDescription key="fontDescription" type="system" pointSize="14"/>
<object class="IBProxyObject" id="841351856"> <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
<string key="IBProxiedObjectIdentifier">IBFilesOwner</string> </textView>
<string key="targetRuntimeIdentifier">IBIPadFramework</string> <button opaque="NO" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="51">
</object> <rect key="frame" x="580" y="62" width="48" height="36"/>
<object class="IBProxyObject" id="606714003"> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
<string key="IBProxiedObjectIdentifier">IBFirstResponder</string> <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<string key="targetRuntimeIdentifier">IBIPadFramework</string> <inset key="imageEdgeInsets" minX="4" minY="2" maxX="4" maxY="2"/>
</object> <state key="normal" image="story_share_twitter.png">
<object class="IBUIView" id="766721923"> <color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
<reference key="NSNextResponder"/> <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
<int key="NSvFlags">319</int> </state>
<array class="NSMutableArray" key="NSSubviews"> <state key="selected" image="story_share_twitter_active.png" backgroundImage="white_spacer.png"/>
<object class="IBUITextView" id="993868796"> <state key="highlighted">
<reference key="NSNextResponder" ref="766721923"/> <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<int key="NSvFlags">303</int> </state>
<string key="NSFrame">{{20, 15}, {664, 39}}</string> <connections>
<reference key="NSSuperview" ref="766721923"/> <action selector="doToggleButton:" destination="-1" eventType="touchUpInside" id="58"/>
<string key="NSReuseIdentifierKey">_NS:9</string> </connections>
<object class="NSColor" key="IBUIBackgroundColor"> </button>
<int key="NSColorSpace">1</int> <button opaque="NO" tag="3" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="52">
<bytes key="NSRGB">MSAxIDEAA</bytes> <rect key="frame" x="524" y="62" width="48" height="36"/>
</object> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
<bool key="IBUIClipsSubviews">YES</bool> <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<bool key="IBUIMultipleTouchEnabled">YES</bool> <inset key="imageEdgeInsets" minX="4" minY="2" maxX="4" maxY="2"/>
<string key="targetRuntimeIdentifier">IBIPadFramework</string> <state key="normal" image="story_share_appnet.png">
<bool key="IBUIShowsHorizontalScrollIndicator">NO</bool> <color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
<string key="IBUIText"/> <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
<object class="IBUITextInputTraits" key="IBUITextInputTraits"> </state>
<int key="IBUIAutocapitalizationType">2</int> <state key="selected" image="story_share_appnet_active.png" backgroundImage="white_spacer.png"/>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> <state key="highlighted">
</object> <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<object class="IBUIFontDescription" key="IBUIFontDescription"> </state>
<int key="type">1</int> <connections>
<double key="pointSize">14</double> <action selector="doToggleButton:" destination="-1" eventType="touchUpInside" id="57"/>
</object> </connections>
<object class="NSFont" key="IBUIFont"> </button>
<string key="NSName">Helvetica</string> <button opaque="NO" tag="2" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="53">
<double key="NSSize">14</double> <rect key="frame" x="636" y="62" width="48" height="36"/>
<int key="NSfFlags">16</int> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
</object> <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
</object> <inset key="imageEdgeInsets" minX="4" minY="2" maxX="4" maxY="2"/>
<object class="IBUIButton" id="489631384"> <state key="normal" image="story_share_facebook.png">
<reference key="NSNextResponder" ref="766721923"/> <color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
<int key="NSvFlags">265</int> <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
<string key="NSFrame">{{580, 62}, {48, 36}}</string> </state>
<reference key="NSSuperview" ref="766721923"/> <state key="selected" image="story_share_facebook_active.png" backgroundImage="white_spacer.png"/>
<reference key="NSNextKeyView" ref="578316005"/> <state key="highlighted">
<string key="NSReuseIdentifierKey">_NS:9</string> <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<bool key="IBUIOpaque">NO</bool> </state>
<int key="IBUITag">1</int> <connections>
<string key="targetRuntimeIdentifier">IBIPadFramework</string> <action selector="doToggleButton:" destination="-1" eventType="touchUpInside" id="59"/>
<int key="IBUIContentHorizontalAlignment">0</int> </connections>
<int key="IBUIContentVerticalAlignment">0</int> </button>
<double key="IBUIImageEdgeInsets.top">2</double> </subviews>
<double key="IBUIImageEdgeInsets.bottom">2</double> <color key="backgroundColor" white="0.94625342150000002" alpha="1" colorSpace="calibratedWhite"/>
<double key="IBUIImageEdgeInsets.left">4</double> <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<double key="IBUIImageEdgeInsets.right">4</double> </view>
<object class="NSColor" key="IBUIHighlightedTitleColor" id="399517210"> </objects>
<int key="NSColorSpace">3</int> <resources>
<bytes key="NSWhite">MQA</bytes> <image name="story_share_appnet.png" width="12" height="12"/>
</object> <image name="story_share_appnet_active.png" width="12" height="12"/>
<object class="NSColor" key="IBUINormalTitleColor"> <image name="story_share_facebook.png" width="12" height="12"/>
<int key="NSColorSpace">1</int> <image name="story_share_facebook_active.png" width="12" height="12"/>
<bytes key="NSRGB">MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA</bytes> <image name="story_share_twitter.png" width="12" height="12"/>
</object> <image name="story_share_twitter_active.png" width="12" height="12"/>
<object class="NSColor" key="IBUINormalTitleShadowColor" id="485559184"> <image name="white_spacer.png" width="1" height="1"/>
<int key="NSColorSpace">3</int> </resources>
<bytes key="NSWhite">MC41AA</bytes> </document>
</object>
<object class="NSCustomResource" key="IBUISelectedImage">
<string key="NSClassName">NSImage</string>
<string key="NSResourceName">story_share_twitter_active.png</string>
</object>
<object class="NSCustomResource" key="IBUINormalImage">
<string key="NSClassName">NSImage</string>
<string key="NSResourceName">story_share_twitter.png</string>
</object>
<object class="NSCustomResource" key="IBUISelectedBackgroundImage" id="591220768">
<string key="NSClassName">NSImage</string>
<string key="NSResourceName">white_spacer.png</string>
</object>
<object class="IBUIFontDescription" key="IBUIFontDescription" id="562180707">
<int key="type">2</int>
<double key="pointSize">15</double>
</object>
<object class="NSFont" key="IBUIFont" id="234883255">
<string key="NSName">Helvetica-Bold</string>
<double key="NSSize">15</double>
<int key="NSfFlags">16</int>
</object>
</object>
<object class="IBUIButton" id="290108663">
<reference key="NSNextResponder" ref="766721923"/>
<int key="NSvFlags">265</int>
<string key="NSFrame">{{524, 62}, {48, 36}}</string>
<reference key="NSSuperview" ref="766721923"/>
<reference key="NSNextKeyView" ref="489631384"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="IBUIOpaque">NO</bool>
<int key="IBUITag">3</int>
<string key="targetRuntimeIdentifier">IBIPadFramework</string>
<int key="IBUIContentHorizontalAlignment">0</int>
<int key="IBUIContentVerticalAlignment">0</int>
<double key="IBUIImageEdgeInsets.top">2</double>
<double key="IBUIImageEdgeInsets.bottom">2</double>
<double key="IBUIImageEdgeInsets.left">4</double>
<double key="IBUIImageEdgeInsets.right">4</double>
<reference key="IBUIHighlightedTitleColor" ref="399517210"/>
<object class="NSColor" key="IBUINormalTitleColor">
<int key="NSColorSpace">1</int>
<bytes key="NSRGB">MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA</bytes>
</object>
<reference key="IBUINormalTitleShadowColor" ref="485559184"/>
<object class="NSCustomResource" key="IBUISelectedImage">
<string key="NSClassName">NSImage</string>
<string key="NSResourceName">story_share_appnet_active.png</string>
</object>
<object class="NSCustomResource" key="IBUINormalImage">
<string key="NSClassName">NSImage</string>
<string key="NSResourceName">story_share_appnet.png</string>
</object>
<reference key="IBUISelectedBackgroundImage" ref="591220768"/>
<reference key="IBUIFontDescription" ref="562180707"/>
<reference key="IBUIFont" ref="234883255"/>
</object>
<object class="IBUIButton" id="578316005">
<reference key="NSNextResponder" ref="766721923"/>
<int key="NSvFlags">265</int>
<string key="NSFrame">{{636, 62}, {48, 36}}</string>
<reference key="NSSuperview" ref="766721923"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="IBUIOpaque">NO</bool>
<int key="IBUITag">2</int>
<string key="targetRuntimeIdentifier">IBIPadFramework</string>
<int key="IBUIContentHorizontalAlignment">0</int>
<int key="IBUIContentVerticalAlignment">0</int>
<double key="IBUIImageEdgeInsets.top">2</double>
<double key="IBUIImageEdgeInsets.bottom">2</double>
<double key="IBUIImageEdgeInsets.left">4</double>
<double key="IBUIImageEdgeInsets.right">4</double>
<reference key="IBUIHighlightedTitleColor" ref="399517210"/>
<object class="NSColor" key="IBUINormalTitleColor">
<int key="NSColorSpace">1</int>
<bytes key="NSRGB">MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA</bytes>
</object>
<reference key="IBUINormalTitleShadowColor" ref="485559184"/>
<object class="NSCustomResource" key="IBUISelectedImage">
<string key="NSClassName">NSImage</string>
<string key="NSResourceName">story_share_facebook_active.png</string>
</object>
<object class="NSCustomResource" key="IBUINormalImage">
<string key="NSClassName">NSImage</string>
<string key="NSResourceName">story_share_facebook.png</string>
</object>
<reference key="IBUISelectedBackgroundImage" ref="591220768"/>
<reference key="IBUIFontDescription" ref="562180707"/>
<reference key="IBUIFont" ref="234883255"/>
</object>
</array>
<string key="NSFrameSize">{704, 100}</string>
<reference key="NSSuperview"/>
<object class="NSColor" key="IBUIBackgroundColor">
<int key="NSColorSpace">2</int>
<bytes key="NSRGB">MC45MDk4MDM5ODY1IDAuOTE3NjQ3MTIzMyAwLjg5NDExNzcxMwA</bytes>
</object>
<bool key="IBUIClearsContextBeforeDrawing">NO</bool>
<object class="IBUISimulatedSizeMetrics" key="IBUISimulatedDestinationMetrics">
<string key="IBUISimulatedSizeMetricsClass">IBUISimulatedFreeformSizeMetricsSentinel</string>
<string key="IBUIDisplayName">Freeform</string>
</object>
<string key="targetRuntimeIdentifier">IBIPadFramework</string>
</object>
</array>
<object class="IBObjectContainer" key="IBDocument.Objects">
<array class="NSMutableArray" key="connectionRecords">
<object class="IBConnectionRecord">
<object class="IBCocoaTouchOutletConnection" key="connection">
<string key="label">view</string>
<reference key="source" ref="841351856"/>
<reference key="destination" ref="766721923"/>
</object>
<int key="connectionID">3</int>
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchOutletConnection" key="connection">
<string key="label">commentField</string>
<reference key="source" ref="841351856"/>
<reference key="destination" ref="993868796"/>
</object>
<int key="connectionID">29</int>
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchOutletConnection" key="connection">
<string key="label">twitterButton</string>
<reference key="source" ref="841351856"/>
<reference key="destination" ref="489631384"/>
</object>
<int key="connectionID">54</int>
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchOutletConnection" key="connection">
<string key="label">facebookButton</string>
<reference key="source" ref="841351856"/>
<reference key="destination" ref="578316005"/>
</object>
<int key="connectionID">55</int>
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchOutletConnection" key="connection">
<string key="label">appdotnetButton</string>
<reference key="source" ref="841351856"/>
<reference key="destination" ref="290108663"/>
</object>
<int key="connectionID">56</int>
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchEventConnection" key="connection">
<string key="label">doToggleButton:</string>
<reference key="source" ref="489631384"/>
<reference key="destination" ref="841351856"/>
<int key="IBEventType">7</int>
</object>
<int key="connectionID">58</int>
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchEventConnection" key="connection">
<string key="label">doToggleButton:</string>
<reference key="source" ref="290108663"/>
<reference key="destination" ref="841351856"/>
<int key="IBEventType">7</int>
</object>
<int key="connectionID">57</int>
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchEventConnection" key="connection">
<string key="label">doToggleButton:</string>
<reference key="source" ref="578316005"/>
<reference key="destination" ref="841351856"/>
<int key="IBEventType">7</int>
</object>
<int key="connectionID">59</int>
</object>
</array>
<object class="IBMutableOrderedSet" key="objectRecords">
<array key="orderedObjects">
<object class="IBObjectRecord">
<int key="objectID">0</int>
<array key="object" id="0"/>
<reference key="children" ref="1000"/>
<nil key="parent"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">-1</int>
<reference key="object" ref="841351856"/>
<reference key="parent" ref="0"/>
<string key="objectName">File's Owner</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">-2</int>
<reference key="object" ref="606714003"/>
<reference key="parent" ref="0"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">2</int>
<reference key="object" ref="766721923"/>
<array class="NSMutableArray" key="children">
<reference ref="993868796"/>
<reference ref="489631384"/>
<reference ref="290108663"/>
<reference ref="578316005"/>
</array>
<reference key="parent" ref="0"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">19</int>
<reference key="object" ref="993868796"/>
<reference key="parent" ref="766721923"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">51</int>
<reference key="object" ref="489631384"/>
<reference key="parent" ref="766721923"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">52</int>
<reference key="object" ref="290108663"/>
<reference key="parent" ref="766721923"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">53</int>
<reference key="object" ref="578316005"/>
<reference key="parent" ref="766721923"/>
</object>
</array>
</object>
<dictionary class="NSMutableDictionary" key="flattenedProperties">
<string key="-1.CustomClassName">ShareViewController</string>
<string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="-2.CustomClassName">UIResponder</string>
<string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="19.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="2.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="51.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<real value="2" key="51.IBUIButtonInspectorSelectedEdgeInsetMetadataKey"/>
<real value="2" key="51.IBUIButtonInspectorSelectedStateConfigurationMetadataKey"/>
<string key="52.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<real value="0.0" key="52.IBUIButtonInspectorSelectedEdgeInsetMetadataKey"/>
<real value="2" key="52.IBUIButtonInspectorSelectedStateConfigurationMetadataKey"/>
<string key="53.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<real value="2" key="53.IBUIButtonInspectorSelectedEdgeInsetMetadataKey"/>
<real value="2" key="53.IBUIButtonInspectorSelectedStateConfigurationMetadataKey"/>
</dictionary>
<dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
<nil key="activeLocalization"/>
<dictionary class="NSMutableDictionary" key="localizations"/>
<nil key="sourceID"/>
<int key="maxID">59</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes"/>
<int key="IBDocument.localizationMode">0</int>
<string key="IBDocument.TargetRuntimeIdentifier">IBIPadFramework</string>
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS</string>
<real value="1552" key="NS.object.0"/>
</object>
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
<int key="IBDocument.defaultPropertyAccessControl">3</int>
<dictionary class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
<string key="story_share_appnet.png">{12, 12}</string>
<string key="story_share_appnet_active.png">{12, 12}</string>
<string key="story_share_facebook.png">{12, 12}</string>
<string key="story_share_facebook_active.png">{12, 12}</string>
<string key="story_share_twitter.png">{12, 12}</string>
<string key="story_share_twitter_active.png">{12, 12}</string>
<string key="white_spacer.png">{1, 1}</string>
</dictionary>
<string key="IBCocoaTouchPluginVersion">2083</string>
</data>
</archive>

View file

@ -58,13 +58,14 @@ static UIFont *indicatorFont = nil;
font = [UIFont fontWithName:@"Helvetica-Bold" size:11]; font = [UIFont fontWithName:@"Helvetica-Bold" size:11];
textColor = UIColorFromRGB(0x606060); textColor = UIColorFromRGB(0x606060);
[textColor set];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle defaultParagraphStyle] mutableCopy];
[self.siteTitle paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;
drawInRect:CGRectMake(leftMargin + 20, 6, rect.size.width - 20, 21) paragraphStyle.alignment = NSTextAlignmentLeft;
withFont:font [self.siteTitle drawInRect:CGRectMake(leftMargin + 20, 6, rect.size.width - 20, 21)
lineBreakMode:NSLineBreakByTruncatingTail withAttributes:@{NSFontAttributeName: font,
alignment:NSTextAlignmentLeft]; NSForegroundColorAttributeName: textColor,
NSParagraphStyleAttributeName: paragraphStyle}];
// feed bar // feed bar
CGContextSetStrokeColor(context, CGColorGetComponents([self.feedColorBar CGColor])); //feedColorBarTopBorder CGContextSetStrokeColor(context, CGColorGetComponents([self.feedColorBar CGColor])); //feedColorBarTopBorder
@ -77,7 +78,7 @@ static UIFont *indicatorFont = nil;
CGContextSetStrokeColor(context, CGColorGetComponents([self.feedColorBar CGColor])); //feedColorBarTopBorder CGContextSetStrokeColor(context, CGColorGetComponents([self.feedColorBar CGColor])); //feedColorBarTopBorder
CGContextSetLineWidth(context, 6.0f); CGContextSetLineWidth(context, 6.0f);
CGContextBeginPath(context); CGContextBeginPath(context);
float width = self.bounds.size.width - 20.0f; float width = self.bounds.size.width - 3.0f;
CGContextMoveToPoint(context, width, 1.0f); CGContextMoveToPoint(context, width, 1.0f);
CGContextAddLineToPoint(context, width, self.frame.size.height); CGContextAddLineToPoint(context, width, self.frame.size.height);
CGContextStrokePath(context); CGContextStrokePath(context);

View file

@ -17,6 +17,7 @@
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
activityLabel = nil; activityLabel = nil;
faviconView = nil; faviconView = nil;
self.separatorInset = UIEdgeInsetsMake(0, 52, 0, 0);
// create favicon and label in view // create favicon and label in view
UIImageView *favicon = [[UIImageView alloc] initWithFrame:CGRectZero]; UIImageView *favicon = [[UIImageView alloc] initWithFrame:CGRectZero];
@ -42,25 +43,26 @@
[super layoutSubviews]; [super layoutSubviews];
// determine outer bounds // determine outer bounds
CGRect contentRect = self.contentView.bounds; [self.activityLabel sizeToFit];
CGRect contentRect = self.frame;
CGRect labelFrame = self.activityLabel.frame;
// position avatar to bounds // position avatar to bounds
self.faviconView.frame = CGRectMake(leftMargin, topMargin, avatarSize, avatarSize); self.faviconView.frame = CGRectMake(leftMargin, topMargin, avatarSize, avatarSize);
// position label to bounds // position label to bounds
CGRect labelRect = contentRect; labelFrame.origin.x = leftMargin*2 + avatarSize;
labelRect.origin.x = labelRect.origin.x + leftMargin + avatarSize + leftMargin; labelFrame.origin.y = topMargin - 1;
labelRect.origin.y = labelRect.origin.y + topMargin - 1; labelFrame.size.width = contentRect.size.width - leftMargin - avatarSize - leftMargin - rightMargin - 20;
labelRect.size.width = contentRect.size.width - leftMargin - avatarSize - leftMargin - rightMargin; labelFrame.size.height = contentRect.size.height - topMargin - bottomMargin;
labelRect.size.height = contentRect.size.height - topMargin - bottomMargin; self.activityLabel.frame = labelFrame;
self.activityLabel.frame = labelRect;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
self.activityLabel.backgroundColor = UIColorFromRGB(0xd7dadf); self.activityLabel.backgroundColor = UIColorFromRGB(0xd7dadf);
} else { } else {
self.activityLabel.backgroundColor = UIColorFromRGB(0xf6f6f6); self.activityLabel.backgroundColor = UIColorFromRGB(0xf6f6f6);
} }
self.activityLabel.backgroundColor = [UIColor clearColor]; self.activityLabel.backgroundColor = [UIColor clearColor];
[self.activityLabel sizeToFit];
} }
@end @end

View file

@ -17,6 +17,7 @@
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
interactionLabel = nil; interactionLabel = nil;
avatarView = nil; avatarView = nil;
self.separatorInset = UIEdgeInsetsMake(0, 52, 0, 0);
// create favicon and label in view // create favicon and label in view
UIImageView *favicon = [[UIImageView alloc] initWithFrame:CGRectZero]; UIImageView *favicon = [[UIImageView alloc] initWithFrame:CGRectZero];
@ -42,25 +43,26 @@
[super layoutSubviews]; [super layoutSubviews];
// determine outer bounds // determine outer bounds
CGRect contentRect = self.contentView.bounds; [self.interactionLabel sizeToFit];
CGRect contentRect = self.frame;
CGRect labelFrame = self.interactionLabel.frame;
// position avatar to bounds // position avatar to bounds
self.avatarView.frame = CGRectMake(leftMargin, topMargin, avatarSize, avatarSize); self.avatarView.frame = CGRectMake(leftMargin, topMargin, avatarSize, avatarSize);
// position label to bounds // position label to bounds
CGRect labelRect = contentRect; labelFrame.origin.x = leftMargin*2 + avatarSize;
labelRect.origin.x = labelRect.origin.x + leftMargin + avatarSize + leftMargin; labelFrame.origin.y = topMargin - 1;
labelRect.origin.y = labelRect.origin.y + topMargin - 1; labelFrame.size.width = contentRect.size.width - leftMargin - avatarSize - leftMargin - rightMargin - 20;
labelRect.size.width = contentRect.size.width - leftMargin - avatarSize - leftMargin - rightMargin; labelFrame.size.height = contentRect.size.height - topMargin - bottomMargin;
labelRect.size.height = contentRect.size.height - topMargin - bottomMargin; self.interactionLabel.frame = labelFrame;
self.interactionLabel.frame = labelRect;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
self.interactionLabel.backgroundColor = UIColorFromRGB(0xd7dadf); self.interactionLabel.backgroundColor = UIColorFromRGB(0xd7dadf);
} else { } else {
self.interactionLabel.backgroundColor = UIColorFromRGB(0xf6f6f6); self.interactionLabel.backgroundColor = UIColorFromRGB(0xf6f6f6);
} }
self.interactionLabel.backgroundColor = [UIColor clearColor]; self.interactionLabel.backgroundColor = [UIColor clearColor];
[self.interactionLabel sizeToFit];
} }
@end @end

View file

@ -18,7 +18,7 @@
NewsBlurAppDelegate *appDelegate; NewsBlurAppDelegate *appDelegate;
NSString *activeStoryId; NSString *activeStoryId;
NSDictionary *activeStory; NSMutableDictionary *activeStory;
UIView *innerView; UIView *innerView;
UIWebView *webView; UIWebView *webView;
NSInteger pageIndex; NSInteger pageIndex;
@ -28,14 +28,15 @@
@property (nonatomic) IBOutlet NewsBlurAppDelegate *appDelegate; @property (nonatomic) IBOutlet NewsBlurAppDelegate *appDelegate;
@property (nonatomic) NSString *activeStoryId; @property (nonatomic) NSString *activeStoryId;
@property (nonatomic, readwrite) NSDictionary *activeStory; @property (nonatomic, readwrite) NSMutableDictionary *activeStory;
@property (nonatomic) IBOutlet UIView *innerView; @property (nonatomic) IBOutlet UIView *innerView;
@property (nonatomic) IBOutlet UIWebView *webView; @property (nonatomic) IBOutlet UIWebView *webView;
@property (nonatomic) IBOutlet UIView *feedTitleGradient; @property (nonatomic) IBOutlet UIView *feedTitleGradient;
@property (nonatomic) IBOutlet UILabel *noStorySelectedLabel; @property (nonatomic) IBOutlet UIView *noStoryMessage;
@property (nonatomic) IBOutlet UIImageView *noStorySelectedImage;
@property (nonatomic, assign) BOOL pullingScrollview; @property (nonatomic, assign) BOOL pullingScrollview;
@property (nonatomic, assign) BOOL inTextView; @property (nonatomic, assign) BOOL inTextView;
@property (nonatomic, assign) BOOL isRecentlyUnread;
@property NSInteger pageIndex; @property NSInteger pageIndex;
@property (nonatomic) MBProgressHUD *storyHUD; @property (nonatomic) MBProgressHUD *storyHUD;

View file

@ -6,6 +6,7 @@
// Copyright 2010 __MyCompanyName__. All rights reserved. // Copyright 2010 __MyCompanyName__. All rights reserved.
// //
#import <AVFoundation/AVFoundation.h>
#import "StoryDetailViewController.h" #import "StoryDetailViewController.h"
#import "NewsBlurAppDelegate.h" #import "NewsBlurAppDelegate.h"
#import "NewsBlurViewController.h" #import "NewsBlurViewController.h"
@ -32,12 +33,12 @@
@synthesize innerView; @synthesize innerView;
@synthesize webView; @synthesize webView;
@synthesize feedTitleGradient; @synthesize feedTitleGradient;
@synthesize noStorySelectedLabel; @synthesize noStoryMessage;
@synthesize noStorySelectedImage;
@synthesize pullingScrollview; @synthesize pullingScrollview;
@synthesize pageIndex; @synthesize pageIndex;
@synthesize storyHUD; @synthesize storyHUD;
@synthesize inTextView; @synthesize inTextView;
@synthesize isRecentlyUnread;
#pragma mark - #pragma mark -
@ -56,6 +57,10 @@
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback
error:nil];
self.webView.scalesPageToFit = YES; self.webView.scalesPageToFit = YES;
self.webView.multipleTouchEnabled = NO; self.webView.multipleTouchEnabled = NO;
@ -65,6 +70,7 @@
[self.webView.scrollView addObserver:self forKeyPath:@"contentOffset" [self.webView.scrollView addObserver:self forKeyPath:@"contentOffset"
options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context:nil]; context:nil];
self.pageIndex = -2; self.pageIndex = -2;
self.inTextView = NO; self.inTextView = NO;
} }
@ -75,7 +81,6 @@
- (void)viewDidUnload { - (void)viewDidUnload {
[self setInnerView:nil]; [self setInnerView:nil];
[self setNoStorySelectedLabel:nil];
[super viewDidUnload]; [super viewDidUnload];
} }
@ -98,16 +103,14 @@
- (void)initStory { - (void)initStory {
appDelegate.inStoryDetail = YES; appDelegate.inStoryDetail = YES;
self.noStorySelectedLabel.hidden = YES; self.noStoryMessage.hidden = YES;
self.noStorySelectedImage.hidden = YES;
self.webView.hidden = NO; self.webView.hidden = NO;
[appDelegate hideShareView:NO]; [appDelegate hideShareView:NO];
} }
- (void)hideNoStoryMessage { - (void)hideNoStoryMessage {
self.noStorySelectedLabel.hidden = YES; self.noStoryMessage.hidden = YES;
self.noStorySelectedImage.hidden = YES;
} }
- (void)drawStory { - (void)drawStory {
@ -278,13 +281,13 @@
- (void)clearStory { - (void)clearStory {
self.activeStoryId = nil; self.activeStoryId = nil;
[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"about:blank"]]]; [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"about:blank"]]];
[MBProgressHUD hideHUDForView:self.webView animated:NO];
} }
- (void)hideStory { - (void)hideStory {
self.activeStoryId = nil; self.activeStoryId = nil;
self.webView.hidden = YES; self.webView.hidden = YES;
self.noStorySelectedLabel.hidden = NO; self.noStoryMessage.hidden = NO;
self.noStorySelectedImage.hidden = NO;
} }
#pragma mark - #pragma mark -
@ -338,6 +341,13 @@
[self.activeStory objectForKey:@"starred_date"]]; [self.activeStory objectForKey:@"starred_date"]];
} }
NSString *storyUnread = @"";
if (self.isRecentlyUnread && [appDelegate isStoryUnread:self.activeStory]) {
NSInteger score = [NewsBlurAppDelegate computeStoryScore:[self.activeStory objectForKey:@"intelligence"]];
storyUnread = [NSString stringWithFormat:@"<div class=\"NB-story-unread NB-%@\"></div>",
score > 0 ? @"positive" : score < 0 ? @"negative" : @"neutral"];
}
NSString *storyTitle = [self.activeStory objectForKey:@"story_title"]; NSString *storyTitle = [self.activeStory objectForKey:@"story_title"];
NSMutableDictionary *titleClassifiers = [[appDelegate.activeClassifiers objectForKey:feedId] NSMutableDictionary *titleClassifiers = [[appDelegate.activeClassifiers objectForKey:feedId]
objectForKey:@"titles"]; objectForKey:@"titles"];
@ -352,16 +362,23 @@
} }
} }
NSString *storyDate = [Utilities formatLongDateFromTimestamp:[[self.activeStory
objectForKey:@"story_timestamp"]
integerValue]];
NSString *storyHeader = [NSString stringWithFormat:@ NSString *storyHeader = [NSString stringWithFormat:@
"<div class=\"NB-header\"><div class=\"NB-header-inner\">" "<div class=\"NB-header\"><div class=\"NB-header-inner\">"
"<div class=\"NB-story-title\">%@</div>" "<div class=\"NB-story-title\">"
" %@"
" %@"
"</div>"
"<div class=\"NB-story-date\">%@</div>" "<div class=\"NB-story-date\">%@</div>"
"%@" "%@"
"%@" "%@"
"%@" "%@"
"</div></div>", "</div></div>",
storyUnread,
storyTitle, storyTitle,
[self.activeStory objectForKey:@"long_parsed_date"], storyDate,
storyAuthor, storyAuthor,
storyTags, storyTags,
storyStarred]; storyStarred];
@ -903,9 +920,9 @@
- (void)setActiveStoryAtIndex:(NSInteger)activeStoryIndex { - (void)setActiveStoryAtIndex:(NSInteger)activeStoryIndex {
if (activeStoryIndex >= 0) { if (activeStoryIndex >= 0) {
self.activeStory = [appDelegate.activeFeedStories objectAtIndex:activeStoryIndex]; self.activeStory = [[appDelegate.activeFeedStories objectAtIndex:activeStoryIndex] mutableCopy];
} else { } else {
self.activeStory = appDelegate.activeStory; self.activeStory = [appDelegate.activeStory mutableCopy];
} }
} }
@ -988,7 +1005,7 @@ shouldStartLoadWithRequest:(NSURLRequest *)request
} else if ([action isEqualToString:@"share"]) { } else if ([action isEqualToString:@"share"]) {
[self openShareDialog]; [self openShareDialog];
return NO; return NO;
} else if ([action isEqualToString:@"train"]) { } else if ([action isEqualToString:@"train"] && [urlComponents count] > 5) {
[self openTrainingDialog:[[urlComponents objectAtIndex:2] intValue] [self openTrainingDialog:[[urlComponents objectAtIndex:2] intValue]
yCoordinate:[[urlComponents objectAtIndex:3] intValue] yCoordinate:[[urlComponents objectAtIndex:3] intValue]
width:[[urlComponents objectAtIndex:4] intValue] width:[[urlComponents objectAtIndex:4] intValue]
@ -1002,7 +1019,7 @@ shouldStartLoadWithRequest:(NSURLRequest *)request
NSString *tag = [NSString stringWithFormat:@"%@", [urlComponents objectAtIndex:2]]; NSString *tag = [NSString stringWithFormat:@"%@", [urlComponents objectAtIndex:2]];
[self.appDelegate toggleTagClassifier:tag feedId:feedId]; [self.appDelegate toggleTagClassifier:tag feedId:feedId];
return NO; return NO;
} else if ([action isEqualToString:@"show-profile"]) { } else if ([action isEqualToString:@"show-profile"] && [urlComponents count] > 6) {
appDelegate.activeUserProfileId = [NSString stringWithFormat:@"%@", [urlComponents objectAtIndex:2]]; appDelegate.activeUserProfileId = [NSString stringWithFormat:@"%@", [urlComponents objectAtIndex:2]];
for (int i = 0; i < appDelegate.activeFeedUserProfiles.count; i++) { for (int i = 0; i < appDelegate.activeFeedUserProfiles.count; i++) {
@ -1437,6 +1454,7 @@ shouldStartLoadWithRequest:(NSURLRequest *)request
ASIFormDataRequest *request = [self formRequestWithURL:urlString]; ASIFormDataRequest *request = [self formRequestWithURL:urlString];
[request addPostValue:[appDelegate.activeStory objectForKey:@"id"] forKey:@"story_id"]; [request addPostValue:[appDelegate.activeStory objectForKey:@"id"] forKey:@"story_id"];
[request addPostValue:[appDelegate.activeStory objectForKey:@"story_feed_id"] forKey:@"feed_id"]; [request addPostValue:[appDelegate.activeStory objectForKey:@"story_feed_id"] forKey:@"feed_id"];
[request setUserInfo:@{@"storyId": [appDelegate.activeStory objectForKey:@"id"]}];
[request setDidFinishSelector:@selector(finishFetchTextView:)]; [request setDidFinishSelector:@selector(finishFetchTextView:)];
[request setDidFailSelector:@selector(requestFailed:)]; [request setDidFailSelector:@selector(requestFailed:)];
[request setDelegate:self]; [request setDelegate:self];
@ -1461,6 +1479,14 @@ shouldStartLoadWithRequest:(NSURLRequest *)request
return; return;
} }
if (![[request.userInfo objectForKey:@"storyId"]
isEqualToString:[appDelegate.activeStory objectForKey:@"id"]]) {
[MBProgressHUD hideHUDForView:self.webView animated:YES];
self.inTextView = NO;
[appDelegate.storyPageControl setTextButton];
return;
}
NSString *originalText = [[[results objectForKey:@"original_text"]stringByReplacingOccurrencesOfString:@"\'" withString:@"\\'"] NSString *originalText = [[[results objectForKey:@"original_text"]stringByReplacingOccurrencesOfString:@"\'" withString:@"\\'"]
stringByReplacingOccurrencesOfString:@"\n" withString:@" "]; stringByReplacingOccurrencesOfString:@"\n" withString:@" "];
NSString *jsString = [NSString stringWithFormat:@"document.getElementById('NB-story').innerHTML = '%@'; loadImages();", NSString *jsString = [NSString stringWithFormat:@"document.getElementById('NB-story').innerHTML = '%@'; loadImages();",

View file

@ -10,14 +10,13 @@
#import "BaseViewController.h" #import "BaseViewController.h"
#import "NewsBlurAppDelegate.h" #import "NewsBlurAppDelegate.h"
#import "WEPopoverController.h" #import "WEPopoverController.h"
#import "TransparentToolbar.h"
#import "THCircularProgressView.h" #import "THCircularProgressView.h"
@class NewsBlurAppDelegate; @class NewsBlurAppDelegate;
@class ASIHTTPRequest; @class ASIHTTPRequest;
@interface StoryPageControl : BaseViewController @interface StoryPageControl : BaseViewController
<UIScrollViewDelegate, UIPopoverControllerDelegate, WEPopoverControllerDelegate> { <UIScrollViewDelegate, UIPopoverControllerDelegate, UIGestureRecognizerDelegate, WEPopoverControllerDelegate> {
NewsBlurAppDelegate *appDelegate; NewsBlurAppDelegate *appDelegate;
@ -26,9 +25,7 @@
UIButton *buttonNext; UIButton *buttonNext;
UIButton *buttonText; UIButton *buttonText;
UIActivityIndicatorView *loadingIndicator; UIActivityIndicatorView *loadingIndicator;
UIToolbar *bottomPlaceholderToolbar;
UIBarButtonItem *buttonBack; UIBarButtonItem *buttonBack;
TransparentToolbar * rightToolbar;
UIView *traverseView; UIView *traverseView;
UIView *progressView; UIView *progressView;
UIView *progressViewContainer; UIView *progressViewContainer;
@ -56,12 +53,11 @@
@property (nonatomic) IBOutlet UIButton *buttonSend; @property (nonatomic) IBOutlet UIButton *buttonSend;
@property (nonatomic) UIBarButtonItem *buttonBack; @property (nonatomic) UIBarButtonItem *buttonBack;
@property (nonatomic) IBOutlet UIBarButtonItem *buttonAction; @property (nonatomic) IBOutlet UIBarButtonItem *buttonAction;
@property (nonatomic) IBOutlet UIToolbar *bottomPlaceholderToolbar; @property (nonatomic) IBOutlet UIView *bottomSize;
@property (nonatomic) IBOutlet UIBarButtonItem * spacerBarButton; @property (nonatomic) IBOutlet UIBarButtonItem * spacerBarButton;
@property (nonatomic) IBOutlet UIBarButtonItem * spacer2BarButton; @property (nonatomic) IBOutlet UIBarButtonItem * spacer2BarButton;
@property (nonatomic) IBOutlet UIBarButtonItem * spacer3BarButton; @property (nonatomic) IBOutlet UIBarButtonItem * spacer3BarButton;
@property (nonatomic) IBOutlet UIBarButtonItem * separatorBarButton; @property (nonatomic) IBOutlet UIBarButtonItem * separatorBarButton;
@property (nonatomic) IBOutlet TransparentToolbar * rightToolbar;
@property (nonatomic) IBOutlet UIView *traverseView; @property (nonatomic) IBOutlet UIView *traverseView;
@property (nonatomic) IBOutlet UIView *progressView; @property (nonatomic) IBOutlet UIView *progressView;
@property (nonatomic) IBOutlet UIView *progressViewContainer; @property (nonatomic) IBOutlet UIView *progressViewContainer;
@ -74,22 +70,24 @@
@property (assign) BOOL isDraggingScrollview; @property (assign) BOOL isDraggingScrollview;
@property (assign) BOOL waitingForNextUnreadFromServer; @property (assign) BOOL waitingForNextUnreadFromServer;
@property (nonatomic) MBProgressHUD *storyHUD; @property (nonatomic) MBProgressHUD *storyHUD;
@property (nonatomic) int scrollingToPage; @property (nonatomic) NSInteger scrollingToPage;
@property (nonatomic, strong) WEPopoverController *popoverController; @property (nonatomic, strong) WEPopoverController *popoverController;
- (void)resizeScrollView; - (void)resizeScrollView;
- (void)applyNewIndex:(NSInteger)newIndex pageController:(StoryDetailViewController *)pageController; - (void)applyNewIndex:(NSInteger)newIndex pageController:(StoryDetailViewController *)pageController;
- (void)layoutForInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; - (void)layoutForInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;
- (void)adjustDragBar:(UIInterfaceOrientation)orientation;
- (void)transitionFromFeedDetail; - (void)transitionFromFeedDetail;
- (void)resetPages; - (void)resetPages;
- (void)hidePages;
- (void)refreshPages; - (void)refreshPages;
- (void)refreshHeaders; - (void)refreshHeaders;
- (void)setStoryFromScroll; - (void)setStoryFromScroll;
- (void)setStoryFromScroll:(BOOL)force; - (void)setStoryFromScroll:(BOOL)force;
- (void)advanceToNextUnread; - (void)advanceToNextUnread;
- (void)updatePageWithActiveStory:(int)location; - (void)updatePageWithActiveStory:(NSInteger)location;
- (void)changePage:(NSInteger)pageIndex; - (void)changePage:(NSInteger)pageIndex;
- (void)changePage:(NSInteger)pageIndex animated:(BOOL)animated; - (void)changePage:(NSInteger)pageIndex animated:(BOOL)animated;
- (void)requestFailed:(ASIHTTPRequest *)request; - (void)requestFailed:(ASIHTTPRequest *)request;
@ -105,6 +103,7 @@
- (void)finishMarkAsSaved:(ASIFormDataRequest *)request; - (void)finishMarkAsSaved:(ASIFormDataRequest *)request;
- (void)markStoryAsUnsaved; - (void)markStoryAsUnsaved;
- (void)finishMarkAsUnsaved:(ASIFormDataRequest *)request; - (void)finishMarkAsUnsaved:(ASIFormDataRequest *)request;
- (void)failedMarkAsUnread:(ASIFormDataRequest *)request;
- (void)subscribeToBlurblog; - (void)subscribeToBlurblog;
- (IBAction)toggleFontSize:(id)sender; - (IBAction)toggleFontSize:(id)sender;
@ -117,8 +116,8 @@
- (void)flashCheckmarkHud:(NSString *)messageType; - (void)flashCheckmarkHud:(NSString *)messageType;
- (IBAction)openSendToDialog:(id)sender; - (IBAction)openSendToDialog:(id)sender;
- (IBAction)doNextUnreadStory; - (IBAction)doNextUnreadStory:(id)sender;
- (IBAction)doPreviousStory; - (IBAction)doPreviousStory:(id)sender;
- (IBAction)tapProgressBar:(id)sender; - (IBAction)tapProgressBar:(id)sender;
- (IBAction)toggleView:(id)sender; - (IBAction)toggleView:(id)sender;

View file

@ -22,7 +22,6 @@
#import "NBContainerViewController.h" #import "NBContainerViewController.h"
#import "DataUtilities.h" #import "DataUtilities.h"
#import "JSON.h" #import "JSON.h"
#import "TransparentToolbar.h"
#import "UIBarButtonItem+Image.h" #import "UIBarButtonItem+Image.h"
#import "THCircularProgressView.h" #import "THCircularProgressView.h"
#import "FMDatabase.h" #import "FMDatabase.h"
@ -35,7 +34,6 @@
@synthesize circularProgressView; @synthesize circularProgressView;
@synthesize separatorBarButton; @synthesize separatorBarButton;
@synthesize spacerBarButton, spacer2BarButton, spacer3BarButton; @synthesize spacerBarButton, spacer2BarButton, spacer3BarButton;
@synthesize rightToolbar;
@synthesize buttonPrevious; @synthesize buttonPrevious;
@synthesize buttonNext; @synthesize buttonNext;
@synthesize buttonAction; @synthesize buttonAction;
@ -45,7 +43,7 @@
@synthesize originalStoryButton; @synthesize originalStoryButton;
@synthesize subscribeButton; @synthesize subscribeButton;
@synthesize buttonBack; @synthesize buttonBack;
@synthesize bottomPlaceholderToolbar; @synthesize bottomSize;
@synthesize popoverController; @synthesize popoverController;
@synthesize loadingIndicator; @synthesize loadingIndicator;
@synthesize inTouchMove; @synthesize inTouchMove;
@ -66,9 +64,15 @@
} }
- (void)viewDidLoad { - (void)viewDidLoad {
currentPage = [[StoryDetailViewController alloc] initWithNibName:@"StoryDetailViewController" bundle:nil]; currentPage = [[StoryDetailViewController alloc]
nextPage = [[StoryDetailViewController alloc] initWithNibName:@"StoryDetailViewController" bundle:nil]; initWithNibName:@"StoryDetailViewController"
previousPage = [[StoryDetailViewController alloc] initWithNibName:@"StoryDetailViewController" bundle:nil]; bundle:nil];
nextPage = [[StoryDetailViewController alloc]
initWithNibName:@"StoryDetailViewController"
bundle:nil];
previousPage = [[StoryDetailViewController alloc]
initWithNibName:@"StoryDetailViewController"
bundle:nil];
currentPage.appDelegate = appDelegate; currentPage.appDelegate = appDelegate;
nextPage.appDelegate = appDelegate; nextPage.appDelegate = appDelegate;
@ -101,36 +105,49 @@
percentage:20]; percentage:20];
circularProgressView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin; circularProgressView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
[self.traverseView addSubview:circularProgressView]; [self.traverseView addSubview:circularProgressView];
UIView *tapIndicator = [[UIView alloc] initWithFrame:CGRectMake(circularProgressView.frame.origin.x - circularProgressView.frame.size.width / 2, circularProgressView.frame.origin.y - circularProgressView.frame.size.height / 2, circularProgressView.frame.size.width*2, circularProgressView.frame.size.height*2)]; UIView *tapIndicator = [[UIView alloc]
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapProgressBar:)]; initWithFrame:CGRectMake(circularProgressView.frame.origin.x -
circularProgressView.frame.size.width / 2,
circularProgressView.frame.origin.y -
circularProgressView.frame.size.height / 2,
circularProgressView.frame.size.width*2,
circularProgressView.frame.size.height*2)];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:@selector(tapProgressBar:)];
[tapIndicator addGestureRecognizer:tap]; [tapIndicator addGestureRecognizer:tap];
tapIndicator.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin; tapIndicator.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
[self.traverseView insertSubview:tapIndicator aboveSubview:circularProgressView]; [self.traverseView insertSubview:tapIndicator aboveSubview:circularProgressView];
self.loadingIndicator.frame = self.circularProgressView.frame; self.loadingIndicator.frame = self.circularProgressView.frame;
self.buttonNext.titleEdgeInsets = UIEdgeInsetsMake(0, 24, 0, 0);
rightToolbar = [[TransparentToolbar alloc]
initWithFrame:CGRectMake(0, 0, 80, 44)];
spacerBarButton = [[UIBarButtonItem alloc] spacerBarButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace
target:nil action:nil];
spacerBarButton.width = -12; spacerBarButton.width = -12;
spacer2BarButton = [[UIBarButtonItem alloc] spacer2BarButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace
spacer2BarButton.width = -4; target:nil action:nil];
spacer2BarButton.width = -6;
spacer3BarButton = [[UIBarButtonItem alloc] spacer3BarButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace
spacer3BarButton.width = -10; target:nil action:nil];
spacer3BarButton.width = -6;
UIImage *separatorImage = [UIImage imageNamed:@"bar-separator.png"]; UIImage *separatorImage = [UIImage imageNamed:@"bar-separator.png"];
separatorBarButton = [UIBarButtonItem barItemWithImage:separatorImage target:nil action:nil]; separatorBarButton = [UIBarButtonItem barItemWithImage:separatorImage
target:nil
action:nil];
[separatorBarButton setEnabled:NO]; [separatorBarButton setEnabled:NO];
UIImage *settingsImage = [UIImage imageNamed:@"nav_icn_settings.png"]; UIImage *settingsImage = [UIImage imageNamed:@"nav_icn_settings.png"];
fontSettingsButton = [UIBarButtonItem barItemWithImage:settingsImage target:self action:@selector(toggleFontSize:)]; fontSettingsButton = [UIBarButtonItem barItemWithImage:settingsImage
target:self
action:@selector(toggleFontSize:)];
UIImage *markreadImage = [UIImage imageNamed:@"original_button.png"]; UIImage *markreadImage = [UIImage imageNamed:@"original_button.png"];
originalStoryButton = [UIBarButtonItem barItemWithImage:markreadImage target:self action:@selector(showOriginalSubview:)]; originalStoryButton = [UIBarButtonItem barItemWithImage:markreadImage
target:self
action:@selector(showOriginalSubview:)];
UIBarButtonItem *subscribeBtn = [[UIBarButtonItem alloc] UIBarButtonItem *subscribeBtn = [[UIBarButtonItem alloc]
initWithTitle:@"Follow User" initWithTitle:@"Follow User"
@ -143,19 +160,18 @@
// back button // back button
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] UIBarButtonItem *backButton = [[UIBarButtonItem alloc]
initWithTitle:@"All Sites" style:UIBarButtonItemStyleBordered target:self action:@selector(transitionFromFeedDetail)]; initWithTitle:@"All Sites"
style:UIBarButtonItemStyleBordered
target:self
action:@selector(transitionFromFeedDetail)];
self.buttonBack = backButton; self.buttonBack = backButton;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
[rightToolbar setItems: [NSArray arrayWithObjects: self.navigationItem.rightBarButtonItems = [NSArray arrayWithObjects:
spacerBarButton, originalStoryButton,
fontSettingsButton, separatorBarButton,
spacer2BarButton, fontSettingsButton, nil];
separatorBarButton,
spacer3BarButton,
originalStoryButton, nil]];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:rightToolbar];
} }
[self.scrollView addObserver:self forKeyPath:@"contentOffset" [self.scrollView addObserver:self forKeyPath:@"contentOffset"
@ -168,17 +184,22 @@
- (void)viewWillAppear:(BOOL)animated { - (void)viewWillAppear:(BOOL)animated {
[self setNextPreviousButtons]; [self setNextPreviousButtons];
[appDelegate adjustStoryDetailWebView]; [appDelegate adjustStoryDetailWebView];
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
if (!appDelegate.isSocialView) { if (!appDelegate.isSocialView) {
UIImage *titleImage; UIImage *titleImage;
if (appDelegate.isSocialRiverView && [appDelegate.activeFolder isEqualToString:@"river_global"]) { if (appDelegate.isSocialRiverView && [appDelegate.activeFolder
isEqualToString:@"river_global"]) {
titleImage = [UIImage imageNamed:@"ak-icon-global.png"]; titleImage = [UIImage imageNamed:@"ak-icon-global.png"];
} else if (appDelegate.isSocialRiverView && [appDelegate.activeFolder isEqualToString:@"river_blurblogs"]) { } else if (appDelegate.isSocialRiverView && [appDelegate.activeFolder
isEqualToString:@"river_blurblogs"]) {
titleImage = [UIImage imageNamed:@"ak-icon-blurblogs.png"]; titleImage = [UIImage imageNamed:@"ak-icon-blurblogs.png"];
} else if (appDelegate.isRiverView && [appDelegate.activeFolder isEqualToString:@"everything"]) { } else if (appDelegate.isRiverView && [appDelegate.activeFolder
isEqualToString:@"everything"]) {
titleImage = [UIImage imageNamed:@"ak-icon-allstories.png"]; titleImage = [UIImage imageNamed:@"ak-icon-allstories.png"];
} else if (appDelegate.isRiverView && [appDelegate.activeFolder isEqualToString:@"saved_stories"]) { } else if (appDelegate.isRiverView && [appDelegate.activeFolder
isEqualToString:@"saved_stories"]) {
titleImage = [UIImage imageNamed:@"clock.png"]; titleImage = [UIImage imageNamed:@"clock.png"];
} else if (appDelegate.isRiverView) { } else if (appDelegate.isRiverView) {
titleImage = [UIImage imageNamed:@"g_icn_folder.png"]; titleImage = [UIImage imageNamed:@"g_icn_folder.png"];
@ -216,17 +237,26 @@
self.traverseView.alpha = 1; self.traverseView.alpha = 1;
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
[self layoutForInterfaceOrientation:orientation]; [self layoutForInterfaceOrientation:orientation];
[self adjustDragBar:orientation];
} }
- (void)viewDidAppear:(BOOL)animated { - (void)viewDidAppear:(BOOL)animated {
// set the subscribeButton flag // set the subscribeButton flag
if (appDelegate.isTryFeedView) { if (appDelegate.isTryFeedView && UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
self.subscribeButton.title = [NSString stringWithFormat:@"Follow %@", [appDelegate.activeFeed objectForKey:@"username"]]; self.subscribeButton.title = [NSString stringWithFormat:@"Follow %@",
[appDelegate.activeFeed objectForKey:@"username"]];
self.navigationItem.leftBarButtonItem = self.subscribeButton; self.navigationItem.leftBarButtonItem = self.subscribeButton;
// self.subscribeButton.tintColor = UIColorFromRGB(0x0a6720); // self.subscribeButton.tintColor = UIColorFromRGB(0x0a6720);
} }
appDelegate.isTryFeedView = NO; appDelegate.isTryFeedView = NO;
[self applyNewIndex:previousPage.pageIndex pageController:previousPage]; [self applyNewIndex:previousPage.pageIndex pageController:previousPage];
previousPage.view.hidden = NO;
}
- (void)viewWillDisappear:(BOOL)animated {
previousPage.view.hidden = YES;
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
} }
- (void)transitionFromFeedDetail { - (void)transitionFromFeedDetail {
@ -237,7 +267,8 @@
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
} }
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration {
if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation)) { if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation)) {
NSLog(@"Rotate: %f,%f",self.view.frame.size.width,self.view.frame.size.height); NSLog(@"Rotate: %f,%f",self.view.frame.size.width,self.view.frame.size.height);
@ -246,6 +277,7 @@
} }
[self layoutForInterfaceOrientation:toInterfaceOrientation]; [self layoutForInterfaceOrientation:toInterfaceOrientation];
[self adjustDragBar:toInterfaceOrientation];
} }
- (void)layoutForInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { - (void)layoutForInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
@ -258,15 +290,48 @@
} }
} }
- (void)adjustDragBar:(UIInterfaceOrientation)orientation {
CGRect scrollViewFrame = self.scrollView.frame;
CGRect traverseViewFrame = self.traverseView.frame;
if (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad ||
UIInterfaceOrientationIsLandscape(orientation)) {
scrollViewFrame.size.height = self.view.frame.size.height;
self.bottomSize.hidden = YES;
} else {
scrollViewFrame.size.height = self.view.frame.size.height - 12;
self.bottomSize.hidden = NO;
}
self.scrollView.frame = scrollViewFrame;
traverseViewFrame.origin.y = scrollViewFrame.size.height - traverseViewFrame.size.height;
self.traverseView.frame = traverseViewFrame;
}
- (void)highlightButton:(UIButton *)b {
if (![b isKindOfClass:[UIButton class]]) return;
[b setHighlighted:YES];
}
- (void)unhighlightButton:(UIButton *)b {
if (![b isKindOfClass:[UIButton class]]) return;
[b setHighlighted:NO];
}
- (IBAction)beginTouchDown:(UIButton *)sender {
[self performSelector:@selector(highlightButton:) withObject:sender afterDelay:0.0];
}
- (IBAction)endTouchDown:(UIButton *)sender {
if (!sender) return;
[self performSelector:@selector(unhighlightButton:) withObject:sender afterDelay:0.2];
}
- (void)resetPages { - (void)resetPages {
[currentPage clearStory]; [currentPage clearStory];
[nextPage clearStory]; [nextPage clearStory];
[previousPage clearStory]; [previousPage clearStory];
[currentPage hideStory];
[nextPage hideStory];
[previousPage hideStory];
CGRect frame = self.scrollView.frame; CGRect frame = self.scrollView.frame;
self.scrollView.contentSize = frame.size; self.scrollView.contentSize = frame.size;
@ -278,11 +343,16 @@
currentPage.pageIndex = -2; currentPage.pageIndex = -2;
nextPage.pageIndex = -2; nextPage.pageIndex = -2;
previousPage.pageIndex = -2; previousPage.pageIndex = -2;
}
- (void)hidePages {
[currentPage hideStory];
[nextPage hideStory];
[previousPage hideStory];
} }
- (void)refreshPages { - (void)refreshPages {
int pageIndex = currentPage.pageIndex; NSInteger pageIndex = currentPage.pageIndex;
[self resizeScrollView]; [self resizeScrollView];
[appDelegate adjustStoryDetailWebView]; [appDelegate adjustStoryDetailWebView];
currentPage.pageIndex = -2; currentPage.pageIndex = -2;
@ -294,6 +364,10 @@
} }
- (void)refreshHeaders { - (void)refreshHeaders {
[currentPage setActiveStoryAtIndex:[appDelegate indexOfStoryId:currentPage.activeStoryId]];
[nextPage setActiveStoryAtIndex:[appDelegate indexOfStoryId:nextPage.activeStoryId]];
[previousPage setActiveStoryAtIndex:[appDelegate indexOfStoryId:previousPage.activeStoryId]];
[currentPage refreshHeader]; [currentPage refreshHeader];
[nextPage refreshHeader]; [nextPage refreshHeader];
[previousPage refreshHeader]; [previousPage refreshHeader];
@ -311,13 +385,15 @@
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad && UIInterfaceOrientationIsPortrait(orientation)) { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad &&
UIInterfaceOrientationIsPortrait(orientation)) {
UITouch *theTouch = [touches anyObject]; UITouch *theTouch = [touches anyObject];
if ([theTouch.view isKindOfClass: UIToolbar.class] || [theTouch.view isKindOfClass: UIView.class]) { if ([theTouch.view isKindOfClass: UIToolbar.class] ||
[theTouch.view isKindOfClass: UIView.class]) {
self.inTouchMove = YES; self.inTouchMove = YES;
// CGPoint touchLocation = [theTouch locationInView:self.view]; CGPoint touchLocation = [theTouch locationInView:self.view];
// CGFloat y = touchLocation.y; CGFloat y = touchLocation.y;
// [appDelegate.masterContainerViewController dragStoryToolbar:y]; [appDelegate.masterContainerViewController dragStoryToolbar:y];
} }
} }
} }
@ -325,10 +401,12 @@
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad && UIInterfaceOrientationIsPortrait(orientation)) { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad &&
UIInterfaceOrientationIsPortrait(orientation)) {
UITouch *theTouch = [touches anyObject]; UITouch *theTouch = [touches anyObject];
if (([theTouch.view isKindOfClass: UIToolbar.class] || [theTouch.view isKindOfClass: UIView.class]) && self.inTouchMove) { if (([theTouch.view isKindOfClass: UIToolbar.class] ||
[theTouch.view isKindOfClass: UIView.class]) && self.inTouchMove) {
self.inTouchMove = NO; self.inTouchMove = NO;
[appDelegate.masterContainerViewController adjustFeedDetailScreenForStoryTitles]; [appDelegate.masterContainerViewController adjustFeedDetailScreenForStoryTitles];
} }
@ -338,7 +416,8 @@
#pragma mark - #pragma mark -
#pragma mark Side scroll view #pragma mark Side scroll view
- (void)applyNewIndex:(NSInteger)newIndex pageController:(StoryDetailViewController *)pageController { - (void)applyNewIndex:(NSInteger)newIndex
pageController:(StoryDetailViewController *)pageController {
NSInteger pageCount = [[appDelegate activeFeedStoryLocations] count]; NSInteger pageCount = [[appDelegate activeFeedStoryLocations] count];
BOOL outOfBounds = newIndex >= pageCount || newIndex < 0; BOOL outOfBounds = newIndex >= pageCount || newIndex < 0;
@ -380,12 +459,12 @@
[appDelegate hideStoryDetailView]; [appDelegate hideStoryDetailView];
} }
} else if (!outOfBounds) { } else if (!outOfBounds) {
int location = [appDelegate indexFromLocation:pageController.pageIndex]; NSInteger location = [appDelegate indexFromLocation:pageController.pageIndex];
[pageController setActiveStoryAtIndex:location]; [pageController setActiveStoryAtIndex:location];
[pageController clearStory]; [pageController clearStory];
if (self.isDraggingScrollview || if (self.isDraggingScrollview ||
self.scrollingToPage < 0 || self.scrollingToPage < 0 ||
abs(newIndex - self.scrollingToPage) <= 1) { ABS(newIndex - self.scrollingToPage) <= 1) {
[pageController initStory]; [pageController initStory];
[pageController drawStory]; [pageController drawStory];
} else { } else {
@ -411,7 +490,7 @@
NSInteger upperNumber = lowerNumber + 1; NSInteger upperNumber = lowerNumber + 1;
NSInteger previousNumber = lowerNumber - 1; NSInteger previousNumber = lowerNumber - 1;
int storyCount = [appDelegate.activeFeedStoryLocations count]; NSInteger storyCount = [appDelegate.activeFeedStoryLocations count];
if (storyCount == 0 || lowerNumber > storyCount) return; if (storyCount == 0 || lowerNumber > storyCount) return;
// NSLog(@"Did Scroll: %f = %d (%d/%d/%d)", fractionalPage, lowerNumber, previousPage.pageIndex, currentPage.pageIndex, nextPage.pageIndex); // NSLog(@"Did Scroll: %f = %d (%d/%d/%d)", fractionalPage, lowerNumber, previousPage.pageIndex, currentPage.pageIndex, nextPage.pageIndex);
@ -490,7 +569,10 @@
[self setStoryFromScroll]; [self setStoryFromScroll];
} }
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad && if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad &&
[keyPath isEqual:@"contentOffset"] && [keyPath isEqual:@"contentOffset"] &&
self.isDraggingScrollview) { self.isDraggingScrollview) {
@ -500,7 +582,7 @@
if (![appDelegate.activeFeedStories count]) return; if (![appDelegate.activeFeedStories count]) return;
int storyIndex = [appDelegate indexFromLocation:nearestNumber]; NSInteger storyIndex = [appDelegate indexFromLocation:nearestNumber];
if (storyIndex != [appDelegate indexOfActiveStory]) { if (storyIndex != [appDelegate indexOfActiveStory]) {
appDelegate.activeStory = [appDelegate.activeFeedStories objectAtIndex:storyIndex]; appDelegate.activeStory = [appDelegate.activeFeedStories objectAtIndex:storyIndex];
[appDelegate changeActiveFeedDetailRow]; [appDelegate changeActiveFeedDetailRow];
@ -536,8 +618,6 @@
[self setStoryFromScroll]; [self setStoryFromScroll];
} }
} }
[self markStoryAsRead];
} }
- (void)setStoryFromScroll { - (void)setStoryFromScroll {
@ -577,6 +657,7 @@
nextPage.webView.scrollView.scrollsToTop = NO; nextPage.webView.scrollView.scrollsToTop = NO;
previousPage.webView.scrollView.scrollsToTop = NO; previousPage.webView.scrollView.scrollsToTop = NO;
currentPage.webView.scrollView.scrollsToTop = YES; currentPage.webView.scrollView.scrollsToTop = YES;
currentPage.isRecentlyUnread = NO;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
appDelegate.feedDetailViewController.storyTitlesTable.scrollsToTop = NO; appDelegate.feedDetailViewController.storyTitlesTable.scrollsToTop = NO;
} }
@ -585,7 +666,7 @@
if (self.isDraggingScrollview || self.scrollingToPage == currentPage.pageIndex) { if (self.isDraggingScrollview || self.scrollingToPage == currentPage.pageIndex) {
if (currentPage.pageIndex == -2) return; if (currentPage.pageIndex == -2) return;
self.scrollingToPage = -1; self.scrollingToPage = -1;
int storyIndex = [appDelegate indexFromLocation:currentPage.pageIndex]; NSInteger storyIndex = [appDelegate indexFromLocation:currentPage.pageIndex];
appDelegate.activeStory = [appDelegate.activeFeedStories objectAtIndex:storyIndex]; appDelegate.activeStory = [appDelegate.activeFeedStories objectAtIndex:storyIndex];
[self updatePageWithActiveStory:currentPage.pageIndex]; [self updatePageWithActiveStory:currentPage.pageIndex];
[self markStoryAsRead]; [self markStoryAsRead];
@ -598,23 +679,20 @@
} }
self.waitingForNextUnreadFromServer = NO; self.waitingForNextUnreadFromServer = NO;
[self doNextUnreadStory]; [self doNextUnreadStory:nil];
} }
- (void)updatePageWithActiveStory:(int)location { - (void)updatePageWithActiveStory:(NSInteger)location {
[appDelegate pushReadStory:[appDelegate.activeStory objectForKey:@"id"]]; [appDelegate pushReadStory:[appDelegate.activeStory objectForKey:@"id"]];
self.bottomPlaceholderToolbar.hidden = YES; // self.bottomSize.hidden = YES;
[self.view setNeedsLayout];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[rightToolbar setItems: [NSArray arrayWithObjects: self.navigationItem.rightBarButtonItems = [NSArray arrayWithObjects:
spacerBarButton, originalStoryButton,
fontSettingsButton, separatorBarButton,
spacer2BarButton, fontSettingsButton, nil];
separatorBarButton,
spacer3BarButton,
originalStoryButton, nil]];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:rightToolbar];
} }
[self setNextPreviousButtons]; [self setNextPreviousButtons];
@ -638,50 +716,33 @@
[self informError:@"The server barfed!"]; [self informError:@"The server barfed!"];
} }
- (void)requestFailedMarkStoryRead:(ASIFormDataRequest *)request {
// [self informError:@"Failed to mark story as read"];
NSString *storyFeedId = [request.userInfo objectForKey:@"story_feed_id"];
NSString *storyHash = [request.userInfo objectForKey:@"story_hash"];
[appDelegate.database inDatabase:^(FMDatabase *db) {
[db executeUpdate:@"INSERT INTO queued_read_hashes "
"(story_feed_id, story_hash) VALUES "
"(?, ?)", storyFeedId, storyHash];
}];
appDelegate.hasQueuedReadStories = YES;
}
#pragma mark - #pragma mark -
#pragma mark Actions #pragma mark Actions
- (void)setNextPreviousButtons { - (void)setNextPreviousButtons {
// setting up the PREV BUTTON // setting up the PREV BUTTON
int readStoryCount = [appDelegate.readStories count]; NSInteger readStoryCount = [appDelegate.readStories count];
if (readStoryCount == 0 || if (readStoryCount == 0 ||
(readStoryCount == 1 && (readStoryCount == 1 &&
[appDelegate.readStories lastObject] == [appDelegate.activeStory objectForKey:@"id"])) { [appDelegate.readStories lastObject] == [appDelegate.activeStory objectForKey:@"id"])) {
[buttonPrevious setEnabled:NO]; [buttonPrevious setEnabled:NO];
// buttonPrevious.alpha = 1.0f;
// [buttonAction setImage:[UIImage imageNamed:@"traverse_previous_off"]];
} else { } else {
[buttonPrevious setEnabled:YES]; [buttonPrevious setEnabled:YES];
// buttonPrevious.alpha = 1.0f;
// [buttonAction setImage:[UIImage imageNamed:@"traverse_previous"]];
} }
// setting up the NEXT UNREAD STORY BUTTON // setting up the NEXT UNREAD STORY BUTTON
buttonNext.enabled = YES; buttonNext.enabled = YES;
int nextIndex = [appDelegate indexOfNextUnreadStory]; NSInteger nextIndex = [appDelegate indexOfNextUnreadStory];
int unreadCount = [appDelegate unreadCount]; NSInteger unreadCount = [appDelegate unreadCount];
if ((nextIndex == -1 && unreadCount > 0) || if ((nextIndex == -1 && unreadCount > 0) ||
nextIndex != -1) { nextIndex != -1) {
[buttonNext setTitle:@"NEXT" forState:UIControlStateNormal]; [buttonNext setTitle:[@"Next" uppercaseString] forState:UIControlStateNormal];
[buttonNext setBackgroundImage:[UIImage imageNamed:@"traverse_next.png"] forState:UIControlStateNormal]; [buttonNext setBackgroundImage:[UIImage imageNamed:@"traverse_next.png"]
forState:UIControlStateNormal];
} else { } else {
[buttonNext setTitle:@"DONE" forState:UIControlStateNormal]; [buttonNext setTitle:[@"Done" uppercaseString] forState:UIControlStateNormal];
[buttonNext setBackgroundImage:[UIImage imageNamed:@"traverse_done.png"] forState:UIControlStateNormal]; [buttonNext setBackgroundImage:[UIImage imageNamed:@"traverse_done.png"]
forState:UIControlStateNormal];
} }
float unreads = (float)[appDelegate unreadCount]; float unreads = (float)[appDelegate unreadCount];
@ -707,82 +768,34 @@
[buttonText setTitle:[@"Story" uppercaseString] forState:UIControlStateNormal]; [buttonText setTitle:[@"Story" uppercaseString] forState:UIControlStateNormal];
[buttonText setBackgroundImage:[UIImage imageNamed:@"traverse_text_on.png"] [buttonText setBackgroundImage:[UIImage imageNamed:@"traverse_text_on.png"]
forState:nil]; forState:nil];
self.buttonText.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, -44); self.buttonText.titleEdgeInsets = UIEdgeInsetsMake(0, 26, 0, 0);
} else { } else {
[buttonText setTitle:[@"Text" uppercaseString] forState:UIControlStateNormal]; [buttonText setTitle:[@"Text" uppercaseString] forState:UIControlStateNormal];
[buttonText setBackgroundImage:[UIImage imageNamed:@"traverse_text.png"] [buttonText setBackgroundImage:[UIImage imageNamed:@"traverse_text.png"]
forState:nil]; forState:nil];
self.buttonText.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, -40); self.buttonText.titleEdgeInsets = UIEdgeInsetsMake(0, 22, 0, 0);
} }
} }
- (void)markStoryAsRead { - (void)markStoryAsRead {
// NSLog(@"[appDelegate.activeStory objectForKey:@read_status] intValue] %i", [[appDelegate.activeStory objectForKey:@"read_status"] intValue]); if (!appDelegate.activeStory) return;
if ([[appDelegate.activeStory objectForKey:@"read_status"] intValue] != 1 ||
[[appDelegate.unreadStoryHashes objectForKey:[appDelegate.activeStory objectForKey:@"story_hash"]] boolValue]) { if ([appDelegate isStoryUnread:appDelegate.activeStory]) {
[appDelegate markActiveStoryRead]; [appDelegate markActiveStoryRead];
[self.currentPage refreshHeader];
[appDelegate.feedDetailViewController redrawUnreadStory];
NSString *urlString; NSString *urlString = [NSString stringWithFormat:@"%@/reader/mark_story_hashes_as_read",
if (appDelegate.isSocialView || appDelegate.isSocialRiverView) { NEWSBLUR_URL];
urlString = [NSString stringWithFormat:@"%@/reader/mark_social_stories_as_read",
NEWSBLUR_URL];
} else {
urlString = [NSString stringWithFormat:@"%@/reader/mark_story_as_read",
NEWSBLUR_URL];
}
NSURL *url = [NSURL URLWithString:urlString]; NSURL *url = [NSURL URLWithString:urlString];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url]; ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:[appDelegate.activeStory objectForKey:@"story_hash"]
if (appDelegate.isSocialRiverView) { forKey:@"story_hash"];
// grab the user id from the shared_by_friends [request setUserInfo:@{@"story_feed_id":[appDelegate.activeStory
NSArray *storyId = [NSArray arrayWithObject:[appDelegate.activeStory objectForKey:@"id"]]; objectForKey:@"story_feed_id"],
NSString *friendUserId; @"story_hash":[appDelegate.activeStory
objectForKey:@"story_hash"]}];
if ([[appDelegate.activeStory objectForKey:@"shared_by_friends"] count]) {
friendUserId = [NSString stringWithFormat:@"%@",
[[appDelegate.activeStory objectForKey:@"shared_by_friends"] objectAtIndex:0]];
} else if ([[appDelegate.activeStory objectForKey:@"commented_by_friends"] count]) {
friendUserId = [NSString stringWithFormat:@"%@",
[[appDelegate.activeStory objectForKey:@"commented_by_friends"] objectAtIndex:0]];
} else {
friendUserId = [NSString stringWithFormat:@"%@",
[[appDelegate.activeStory objectForKey:@"share_user_ids"] objectAtIndex:0]];
}
NSDictionary *feedStory = [NSDictionary dictionaryWithObject:storyId
forKey:[NSString stringWithFormat:@"%@",
[appDelegate.activeStory objectForKey:@"story_feed_id"]]];
NSDictionary *usersFeedsStories = [NSDictionary dictionaryWithObject:feedStory
forKey:friendUserId];
[request setPostValue:[usersFeedsStories JSONRepresentation] forKey:@"users_feeds_stories"];
} else if (appDelegate.isSocialView) {
NSArray *storyId = [NSArray arrayWithObject:[appDelegate.activeStory objectForKey:@"id"]];
NSDictionary *feedStory = [NSDictionary dictionaryWithObject:storyId
forKey:[NSString stringWithFormat:@"%@",
[appDelegate.activeStory objectForKey:@"story_feed_id"]]];
NSDictionary *usersFeedsStories = [NSDictionary dictionaryWithObject:feedStory
forKey:[NSString stringWithFormat:@"%@",
[appDelegate.activeStory objectForKey:@"social_user_id"]]];
[request setPostValue:[usersFeedsStories JSONRepresentation] forKey:@"users_feeds_stories"];
} else {
[request setPostValue:[appDelegate.activeStory
objectForKey:@"story_hash"]
forKey:@"story_id"];
[request setPostValue:[appDelegate.activeStory
objectForKey:@"story_feed_id"]
forKey:@"feed_id"];
[request setUserInfo:@{@"story_feed_id":[appDelegate.activeStory
objectForKey:@"story_feed_id"],
@"story_hash":[appDelegate.activeStory
objectForKey:@"story_hash"]}];
}
[request setDidFinishSelector:@selector(finishMarkAsRead:)]; [request setDidFinishSelector:@selector(finishMarkAsRead:)];
[request setDidFailSelector:@selector(requestFailedMarkStoryRead:)]; [request setDidFailSelector:@selector(requestFailedMarkStoryRead:)];
[request setDelegate:self]; [request setDelegate:self];
@ -790,7 +803,6 @@
} }
} }
- (void)finishMarkAsRead:(ASIFormDataRequest *)request { - (void)finishMarkAsRead:(ASIFormDataRequest *)request {
if ([request responseStatusCode] != 200) { if ([request responseStatusCode] != 200) {
return [self requestFailedMarkStoryRead:request]; return [self requestFailedMarkStoryRead:request];
@ -802,7 +814,17 @@
// NSLog(@"results in mark as read is %@", results); // NSLog(@"results in mark as read is %@", results);
} }
- (void)requestFailedMarkStoryRead:(ASIFormDataRequest *)request {
// [self informError:@"Failed to mark story as read"];
NSString *storyFeedId = [request.userInfo objectForKey:@"story_feed_id"];
NSString *storyHash = [request.userInfo objectForKey:@"story_hash"];
[appDelegate queueReadStories:@{storyFeedId: @[storyHash]}];
}
- (IBAction)openSendToDialog:(id)sender { - (IBAction)openSendToDialog:(id)sender {
[self endTouchDown:sender];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[appDelegate.masterContainerViewController showSendToPopover:sender]; [appDelegate.masterContainerViewController showSendToPopover:sender];
} else { } else {
@ -836,7 +858,7 @@
return [self requestFailed:request]; return [self requestFailed:request];
} }
[appDelegate markActiveStorySaved:YES]; [appDelegate markStory:appDelegate.activeStory asSaved:YES];
[appDelegate.feedDetailViewController redrawUnreadStory]; [appDelegate.feedDetailViewController redrawUnreadStory];
[self refreshHeaders]; [self refreshHeaders];
[self.currentPage flashCheckmarkHud:@"saved"]; [self.currentPage flashCheckmarkHud:@"saved"];
@ -868,7 +890,7 @@
return [self requestFailed:request]; return [self requestFailed:request];
} }
[appDelegate markActiveStorySaved:NO]; [appDelegate markStory:appDelegate.activeStory asSaved:NO];
[appDelegate.feedDetailViewController redrawUnreadStory]; [appDelegate.feedDetailViewController redrawUnreadStory];
[self refreshHeaders]; [self refreshHeaders];
[self.currentPage flashCheckmarkHud:@"unsaved"]; [self.currentPage flashCheckmarkHud:@"unsaved"];
@ -889,15 +911,16 @@
forKey:@"feed_id"]; forKey:@"feed_id"];
[request setDidFinishSelector:@selector(finishMarkAsUnread:)]; [request setDidFinishSelector:@selector(finishMarkAsUnread:)];
[request setDidFailSelector:@selector(requestFailed:)]; [request setDidFailSelector:@selector(failedMarkAsUnread:)];
[request setDelegate:self]; [request setDelegate:self];
[request setUserInfo:appDelegate.activeStory];
[request startAsynchronous]; [request startAsynchronous];
} }
} }
- (void)finishMarkAsUnread:(ASIFormDataRequest *)request { - (void)finishMarkAsUnread:(ASIFormDataRequest *)request {
if ([request responseStatusCode] != 200) { if ([request responseStatusCode] != 200) {
return [self requestFailed:request]; return [self failedMarkAsUnread:request];
} }
NSString *responseString = [request responseString]; NSString *responseString = [request responseString];
@ -910,11 +933,32 @@
[appDelegate markActiveStoryUnread]; [appDelegate markActiveStoryUnread];
[appDelegate.feedDetailViewController redrawUnreadStory]; [appDelegate.feedDetailViewController redrawUnreadStory];
currentPage.isRecentlyUnread = YES;
[currentPage refreshHeader];
[self setNextPreviousButtons]; [self setNextPreviousButtons];
[self.currentPage flashCheckmarkHud:@"unread"]; [self.currentPage flashCheckmarkHud:@"unread"];
} }
- (void)failedMarkAsUnread:(ASIFormDataRequest *)request {
NSString *storyFeedId = [request.userInfo objectForKey:@"story_feed_id"];
NSString *storyHash = [request.userInfo objectForKey:@"story_hash"];
BOOL dequeued = [appDelegate dequeueReadStoryHash:storyHash inFeed:storyFeedId];
if (!dequeued) {
[self informError:@"Failed to unread story"];
[appDelegate markStoryRead:storyHash feedId:storyFeedId];
} else {
[appDelegate.unreadStoryHashes setObject:[NSNumber numberWithBool:YES] forKey:storyHash];
[appDelegate markActiveStoryUnread];
[appDelegate.feedDetailViewController redrawUnreadStory];
[self setNextPreviousButtons];
[self.currentPage flashCheckmarkHud:@"unread"];
}
[self refreshHeaders];
}
- (IBAction)showOriginalSubview:(id)sender { - (IBAction)showOriginalSubview:(id)sender {
[appDelegate.masterContainerViewController hidePopover]; [appDelegate.masterContainerViewController hidePopover];
@ -928,13 +972,13 @@
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES]; MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.mode = MBProgressHUDModeText; hud.mode = MBProgressHUDModeText;
hud.removeFromSuperViewOnHide = YES; hud.removeFromSuperViewOnHide = YES;
int unreadCount = appDelegate.unreadCount; NSInteger unreadCount = appDelegate.unreadCount;
if (unreadCount == 0) { if (unreadCount == 0) {
hud.labelText = @"No unread stories"; hud.labelText = @"No unread stories";
} else if (unreadCount == 1) { } else if (unreadCount == 1) {
hud.labelText = @"1 story left"; hud.labelText = @"1 story left";
} else { } else {
hud.labelText = [NSString stringWithFormat:@"%i stories left", unreadCount]; hud.labelText = [NSString stringWithFormat:@"%li stories left", (long)unreadCount];
} }
[hud hide:YES afterDelay:0.8]; [hud hide:YES afterDelay:0.8];
} }
@ -944,6 +988,8 @@
} }
- (IBAction)toggleView:(id)sender { - (IBAction)toggleView:(id)sender {
[self endTouchDown:sender];
[self.currentPage fetchTextView]; [self.currentPage fetchTextView];
} }
@ -995,9 +1041,7 @@
self.storyHUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES]; self.storyHUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
self.storyHUD.labelText = msg; self.storyHUD.labelText = msg;
self.storyHUD.margin = 20.0f; self.storyHUD.margin = 20.0f;
self.currentPage.noStorySelectedLabel.hidden = YES; self.currentPage.noStoryMessage.hidden = YES;
self.nextPage.noStorySelectedLabel.hidden = YES;
self.previousPage.noStorySelectedLabel.hidden = YES;
} }
- (void)flashCheckmarkHud:(NSString *)messageType { - (void)flashCheckmarkHud:(NSString *)messageType {
@ -1007,12 +1051,13 @@
#pragma mark - #pragma mark -
#pragma mark Story Traversal #pragma mark Story Traversal
- (IBAction)doNextUnreadStory { - (IBAction)doNextUnreadStory:(id)sender {
FeedDetailViewController *fdvc = self.appDelegate.feedDetailViewController; FeedDetailViewController *fdvc = self.appDelegate.feedDetailViewController;
int nextLocation = [appDelegate locationOfNextUnreadStory]; NSInteger nextLocation = [appDelegate locationOfNextUnreadStory];
int unreadCount = [appDelegate unreadCount]; NSInteger unreadCount = [appDelegate unreadCount];
[self.loadingIndicator stopAnimating]; [self.loadingIndicator stopAnimating];
[self endTouchDown:sender];
// NSLog(@"doNextUnreadStory: %d (out of %d)", nextLocation, unreadCount); // NSLog(@"doNextUnreadStory: %d (out of %d)", nextLocation, unreadCount);
if (nextLocation == -1 && unreadCount > 0 && if (nextLocation == -1 && unreadCount > 0 &&
@ -1034,7 +1079,8 @@
} }
} }
- (IBAction)doPreviousStory { - (IBAction)doPreviousStory:(id)sender {
[self endTouchDown:sender];
[self.loadingIndicator stopAnimating]; [self.loadingIndicator stopAnimating];
self.circularProgressView.hidden = NO; self.circularProgressView.hidden = NO;
id previousStoryId = [appDelegate popReadStory]; id previousStoryId = [appDelegate popReadStory];
@ -1045,9 +1091,9 @@
animated:YES]; animated:YES];
[appDelegate hideStoryDetailView]; [appDelegate hideStoryDetailView];
} else { } else {
int previousLocation = [appDelegate locationOfStoryId:previousStoryId]; NSInteger previousLocation = [appDelegate locationOfStoryId:previousStoryId];
if (previousLocation == -1) { if (previousLocation == -1) {
return [self doPreviousStory]; return [self doPreviousStory:sender];
} }
// [appDelegate setActiveStory:[[appDelegate activeFeedStories] // [appDelegate setActiveStory:[[appDelegate activeFeedStories]
// objectAtIndex:previousIndex]]; // objectAtIndex:previousIndex]];

File diff suppressed because it is too large Load diff

View file

@ -27,6 +27,7 @@
TrainerWebView *webView; TrainerWebView *webView;
IBOutlet UINavigationBar *navBar; IBOutlet UINavigationBar *navBar;
BOOL feedLoaded;
BOOL feedTrainer; BOOL feedTrainer;
BOOL storyTrainer; BOOL storyTrainer;
} }
@ -37,6 +38,7 @@
@property (nonatomic) IBOutlet UINavigationBar *navBar; @property (nonatomic) IBOutlet UINavigationBar *navBar;
@property (nonatomic, assign) BOOL feedTrainer; @property (nonatomic, assign) BOOL feedTrainer;
@property (nonatomic, assign) BOOL storyTrainer; @property (nonatomic, assign) BOOL storyTrainer;
@property (nonatomic, assign) BOOL feedLoaded;
- (void)refresh; - (void)refresh;
- (NSString *)makeTrainerHTML; - (NSString *)makeTrainerHTML;

View file

@ -11,6 +11,7 @@
#import "StringHelper.h" #import "StringHelper.h"
#import "Utilities.h" #import "Utilities.h"
#import "Base64.h" #import "Base64.h"
#import "AFNetworking.h"
@implementation TrainerViewController @implementation TrainerViewController
@ -20,6 +21,7 @@
@synthesize appDelegate; @synthesize appDelegate;
@synthesize feedTrainer; @synthesize feedTrainer;
@synthesize storyTrainer; @synthesize storyTrainer;
@synthesize feedLoaded;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{ {
@ -64,8 +66,47 @@
nil]]; nil]];
UILabel *titleLabel = (UILabel *)[appDelegate makeFeedTitle:appDelegate.activeFeed]; UILabel *titleLabel = (UILabel *)[appDelegate makeFeedTitle:appDelegate.activeFeed];
navBar.topItem.titleView = titleLabel; self.navigationItem.titleView = titleLabel;
[MBProgressHUD hideHUDForView:self.view animated:NO];
if (!feedLoaded) {
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
HUD.labelText = @"Loading trainer...";
NSString *feedId = [NSString stringWithFormat:@"%@", [appDelegate.activeFeed objectForKey:@"id"]];
NSURL *url = [NSURL URLWithString:[NSString
stringWithFormat:@"%@/reader/feeds_trainer?feed_id=%@",
NEWSBLUR_URL, feedId]];
AFJSONRequestOperation *request = [AFJSONRequestOperation
JSONRequestOperationWithRequest:[NSURLRequest requestWithURL:url]
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
[MBProgressHUD hideHUDForView:self.view animated:YES];
NSDictionary *results = [JSON objectAtIndex:0];
NSMutableDictionary *newClassifiers = [[results objectForKey:@"classifiers"] mutableCopy];
[appDelegate.activeClassifiers setObject:newClassifiers
forKey:feedId];
appDelegate.activePopularAuthors = [results objectForKey:@"feed_authors"];
appDelegate.activePopularTags = [results objectForKey:@"feed_tags"];
[self renderTrainer];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(@"Failed fetch trainer.");
[self informError:@"Could not load trainer"];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC),
dispatch_get_main_queue(), ^{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[appDelegate.masterContainerViewController hidePopover];
} else {
[appDelegate.navigationController dismissViewControllerAnimated:YES completion:nil];
}
});
}];
[request start];
} else {
[self renderTrainer];
}
}
- (void)renderTrainer {
NSString *path = [[NSBundle mainBundle] bundlePath]; NSString *path = [[NSBundle mainBundle] bundlePath];
NSURL *baseURL = [NSURL fileURLWithPath:path]; NSURL *baseURL = [NSURL fileURLWithPath:path];
[self.webView loadHTMLString:[self makeTrainerHTML] baseURL:baseURL]; [self.webView loadHTMLString:[self makeTrainerHTML] baseURL:baseURL];
@ -93,7 +134,7 @@
- (void)viewDidDisappear:(BOOL)animated { - (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated]; [super viewDidDisappear:animated];
[self.webView loadHTMLString:@"about:blank" baseURL:nil]; [self.webView loadHTMLString:@"" baseURL:[NSURL URLWithString:@"about:blank"]];
[[UIMenuController sharedMenuController] setMenuItems:nil]; [[UIMenuController sharedMenuController] setMenuItems:nil];
} }

View file

@ -108,24 +108,25 @@ const int COUNT_HEIGHT = 15;
NSString *psStr = [NSString stringWithFormat:@"%d", ps]; NSString *psStr = [NSString stringWithFormat:@"%d", ps];
CGSize size = [psStr sizeWithFont:indicatorFont]; CGSize size = [psStr sizeWithAttributes:@{NSFontAttributeName: indicatorFont}];
float x_pos = (rr.size.width - size.width) / 2; float x_pos = (rr.size.width - size.width) / 2;
float y_pos = (rr.size.height - size.height) / 2; float y_pos = (rr.size.height - size.height) / 2;
UIColor *psColor;
if (blueCount) { if (blueCount) {
[indicatorBlackColor set]; psColor = indicatorBlackColor;
} else { } else {
[positiveBackgroundShadowColor set]; psColor = positiveBackgroundShadowColor;
} }
[psStr [psStr
drawAtPoint:CGPointMake(rr.origin.x + x_pos, rr.origin.y + y_pos + 1) drawAtPoint:CGPointMake(rr.origin.x + x_pos, rr.origin.y + y_pos + 1)
withFont:indicatorFont]; withAttributes:@{NSFontAttributeName: indicatorFont,
NSForegroundColorAttributeName: psColor}];
[indicatorWhiteColor set];
[psStr [psStr
drawAtPoint:CGPointMake(rr.origin.x + x_pos, rr.origin.y + y_pos) drawAtPoint:CGPointMake(rr.origin.x + x_pos, rr.origin.y + y_pos)
withFont:indicatorFont]; withAttributes:@{NSFontAttributeName: indicatorFont,
NSForegroundColorAttributeName: indicatorWhiteColor}];
} }
if (nt > 0 && appDelegate.selectedIntelligence <= 0) { if (nt > 0 && appDelegate.selectedIntelligence <= 0) {
@ -151,19 +152,19 @@ const int COUNT_HEIGHT = 15;
[UIView drawRoundRectangleInRect:rr withRadius:4]; [UIView drawRoundRectangleInRect:rr withRadius:4];
NSString *ntStr = [NSString stringWithFormat:@"%d", nt]; NSString *ntStr = [NSString stringWithFormat:@"%d", nt];
CGSize size = [ntStr sizeWithFont:indicatorFont]; CGSize size = [ntStr sizeWithAttributes:@{NSFontAttributeName: indicatorFont}];
float x_pos = (rr.size.width - size.width) / 2; float x_pos = (rr.size.width - size.width) / 2;
float y_pos = (rr.size.height - size.height) / 2; float y_pos = (rr.size.height - size.height) / 2;
[neutralBackgroundShadowColor set];
[ntStr [ntStr
drawAtPoint:CGPointMake(rr.origin.x + x_pos, rr.origin.y + y_pos + 1) drawAtPoint:CGPointMake(rr.origin.x + x_pos, rr.origin.y + y_pos + 1)
withFont:indicatorFont]; withAttributes:@{NSFontAttributeName: indicatorFont,
NSForegroundColorAttributeName: neutralBackgroundShadowColor}];
[indicatorWhiteColor set];
[ntStr [ntStr
drawAtPoint:CGPointMake(rr.origin.x + x_pos, rr.origin.y + y_pos) drawAtPoint:CGPointMake(rr.origin.x + x_pos, rr.origin.y + y_pos)
withFont:indicatorFont]; withAttributes:@{NSFontAttributeName: indicatorFont,
NSForegroundColorAttributeName: indicatorWhiteColor}];
} }
} }

View file

@ -31,6 +31,7 @@
@property (nonatomic) NSArray *activitiesArray; @property (nonatomic) NSArray *activitiesArray;
@property (nonatomic) NSString *activitiesUsername; @property (nonatomic) NSString *activitiesUsername;
@property (nonatomic) NSDictionary *userProfile; @property (nonatomic) NSDictionary *userProfile;
@property (nonatomic) ASIHTTPRequest *request;
- (void)getUserProfile; - (void)getUserProfile;
- (void)requestFinished:(ASIHTTPRequest *)request; - (void)requestFinished:(ASIHTTPRequest *)request;

View file

@ -24,6 +24,7 @@
@synthesize activitiesArray; @synthesize activitiesArray;
@synthesize activitiesUsername; @synthesize activitiesUsername;
@synthesize userProfile; @synthesize userProfile;
@synthesize request;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
@ -34,6 +35,12 @@
return self; return self;
} }
- (void)dealloc {
self.profileTable.dataSource = nil;
self.profileTable.delegate = nil;
request.delegate = nil;
[request cancel];
}
- (void)viewDidLoad { - (void)viewDidLoad {
[super viewDidLoad]; [super viewDidLoad];
@ -41,7 +48,7 @@
self.appDelegate = (NewsBlurAppDelegate *)[[UIApplication sharedApplication] delegate]; self.appDelegate = (NewsBlurAppDelegate *)[[UIApplication sharedApplication] delegate];
self.view.frame = self.view.bounds; self.view.frame = self.view.bounds;
self.contentSizeForViewInPopover = self.view.frame.size; self.preferredContentSize = self.view.frame.size;
self.view.backgroundColor = UIColorFromRGB(0xd7dadf); self.view.backgroundColor = UIColorFromRGB(0xd7dadf);
@ -70,7 +77,7 @@
- (void)viewWillAppear:(BOOL)animated { - (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated]; [super viewWillAppear:animated];
CGRect vb = self.view.bounds; CGRect vb = self.view.bounds;
self.contentSizeForViewInPopover = self.view.frame.size; self.preferredContentSize = self.view.frame.size;
self.view.frame = vb; self.view.frame = vb;
self.profileTable.frame = vb; self.profileTable.frame = vb;
self.profileBadge.frame = CGRectMake(0, 0, vb.size.width, 140); self.profileBadge.frame = CGRectMake(0, 0, vb.size.width, 140);
@ -90,7 +97,7 @@
- (void)getUserProfile { - (void)getUserProfile {
self.view.frame = self.view.bounds; self.view.frame = self.view.bounds;
self.contentSizeForViewInPopover = self.view.frame.size; self.preferredContentSize = self.view.frame.size;
self.appDelegate = (NewsBlurAppDelegate *)[[UIApplication sharedApplication] delegate]; self.appDelegate = (NewsBlurAppDelegate *)[[UIApplication sharedApplication] delegate];
[MBProgressHUD hideHUDForView:self.view animated:YES]; [MBProgressHUD hideHUDForView:self.view animated:YES];
@ -104,7 +111,7 @@
appDelegate.activeUserProfileId]; appDelegate.activeUserProfileId];
NSURL *url = [NSURL URLWithString:urlString]; NSURL *url = [NSURL URLWithString:urlString];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url]; request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self]; [request setDelegate:self];
[request setDidFinishSelector:@selector(requestFinished:)]; [request setDidFinishSelector:@selector(requestFinished:)];
@ -112,9 +119,9 @@
[request startAsynchronous]; [request startAsynchronous];
} }
- (void)requestFinished:(ASIHTTPRequest *)request { - (void)requestFinished:(ASIHTTPRequest *)_request {
[MBProgressHUD hideHUDForView:self.view animated:YES]; [MBProgressHUD hideHUDForView:self.view animated:YES];
NSString *responseString = [request responseString]; NSString *responseString = [_request responseString];
NSData *responseData=[responseString dataUsingEncoding:NSUTF8StringEncoding]; NSData *responseData=[responseString dataUsingEncoding:NSUTF8StringEncoding];
NSError *error; NSError *error;
NSDictionary *results = [NSJSONSerialization NSDictionary *results = [NSJSONSerialization
@ -149,8 +156,8 @@
[self.view addSubview:self.profileTable]; [self.view addSubview:self.profileTable];
} }
- (void)requestFailed:(ASIHTTPRequest *)request { - (void)requestFailed:(ASIHTTPRequest *)_request {
NSError *error = [request error]; NSError *error = [_request error];
NSLog(@"Error: %@", error); NSLog(@"Error: %@", error);
[appDelegate informError:error]; [appDelegate informError:error];
} }
@ -205,14 +212,6 @@
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
CGRect vb = self.view.bounds; CGRect vb = self.view.bounds;
// you can only hardcode this due to limitation in apple API that doesn't give you width of grouped cell
int width = 300 - 20;
if (vb.size.width == 480) {
width = 460 - 20;
} else if (vb.size.width == 540) {
width = 478 - 20;
}
if (indexPath.section == 0) { if (indexPath.section == 0) {
ProfileBadge *cell = [tableView ProfileBadge *cell = [tableView
@ -224,7 +223,7 @@
reuseIdentifier:nil]; reuseIdentifier:nil];
} }
[cell refreshWithProfile:self.userProfile showStats:YES withWidth:width + 20]; [cell refreshWithProfile:self.userProfile showStats:YES withWidth:vb.size.width];
cell.selectionStyle = UITableViewCellSelectionStyleNone; cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell; return cell;
@ -240,7 +239,7 @@
cell.accessoryType= UITableViewCellAccessoryDisclosureIndicator; cell.accessoryType= UITableViewCellAccessoryDisclosureIndicator;
[cell setActivity:[self.activitiesArray objectAtIndex:(indexPath.row)] [cell setActivity:[self.activitiesArray objectAtIndex:(indexPath.row)]
withUserProfile:self.userProfile withUserProfile:self.userProfile
withWidth:width]; withWidth:vb.size.width];
return cell; return cell;
} else { } else {
@ -252,13 +251,13 @@
reuseIdentifier:@"FollowGridCellIdentifier"]; reuseIdentifier:@"FollowGridCellIdentifier"];
} }
cell.selectionStyle = UITableViewCellSelectionStyleNone; cell.selectionStyle = UITableViewCellSelectionStyleNone;
[cell refreshWithWidth:width]; [cell refreshWithWidth:vb.size.width];
return cell; return cell;
} }
} }
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
int activitiesCount = [self.activitiesArray count]; NSInteger activitiesCount = [self.activitiesArray count];
// badge is not tappable // badge is not tappable
if (indexPath.section == 0 || indexPath.section == 2) { if (indexPath.section == 0 || indexPath.section == 2) {

View file

@ -22,5 +22,7 @@ void drawLinearGradient(CGContextRef context, CGRect rect, CGColorRef startColor
+ (void)saveimagesToDisk; + (void)saveimagesToDisk;
+ (UIImage *)roundCorneredImage:(UIImage *)orig radius:(CGFloat)r; + (UIImage *)roundCorneredImage:(UIImage *)orig radius:(CGFloat)r;
+ (NSString *)md5:(NSString *)string; + (NSString *)md5:(NSString *)string;
+ (NSString *)formatLongDateFromTimestamp:(NSInteger)timestamp;
+ (NSString *)formatShortDateFromTimestamp:(NSInteger)timestamp;
@end @end

View file

@ -56,7 +56,7 @@ static NSMutableDictionary *imageCache;
+ (UIImage *)getImage:(NSString *)filename isSocial:(BOOL)isSocial { + (UIImage *)getImage:(NSString *)filename isSocial:(BOOL)isSocial {
UIImage *image; UIImage *image;
if (filename && [[imageCache allKeys] containsObject:filename]) { if (filename && [imageCache objectForKey:filename]) {
image = [imageCache objectForKey:filename]; image = [imageCache objectForKey:filename];
} }
@ -144,7 +144,7 @@ static NSMutableDictionary *imageCache;
+ (NSString *)md5:(NSString *)string { + (NSString *)md5:(NSString *)string {
const char *cStr = [string UTF8String]; const char *cStr = [string UTF8String];
unsigned char result[16]; unsigned char result[16];
CC_MD5( cStr, strlen(cStr), result ); // This is the md5 call CC_MD5( cStr, (CC_LONG)strlen(cStr), result ); // This is the md5 call
return [NSString stringWithFormat: return [NSString stringWithFormat:
@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
result[0], result[1], result[2], result[3], result[0], result[1], result[2], result[3],
@ -154,4 +154,117 @@ static NSMutableDictionary *imageCache;
]; ];
} }
+ (NSString *)formatLongDateFromTimestamp:(NSInteger)timestamp {
if (!timestamp) timestamp = [[NSDate date] timeIntervalSince1970];
NSDate *date = [NSDate dateWithTimeIntervalSince1970:(double)timestamp];
static NSDateFormatter *dateFormatter = nil;
static NSDateFormatter *todayFormatter = nil;
static NSDateFormatter *yesterdayFormatter = nil;
static NSDateFormatter *formatterPeriod = nil;
NSDate *today = [NSDate date];
NSDateComponents *components = [[NSCalendar currentCalendar]
components:NSIntegerMax
fromDate:today];
[components setHour:0];
[components setMinute:0];
[components setSecond:0];
NSDate *midnight = [[NSCalendar currentCalendar] dateFromComponents:components];
NSDate *yesterday = [NSDate dateWithTimeInterval:-60*60*24 sinceDate:midnight];
if (!dateFormatter || !todayFormatter || !yesterdayFormatter || !formatterPeriod) {
dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"EEEE, MMMM d'Sth', y h:mm"];
todayFormatter = [[NSDateFormatter alloc] init];
[todayFormatter setDateFormat:@"'Today', MMMM d'Sth' h:mm"];
yesterdayFormatter = [[NSDateFormatter alloc] init];
[yesterdayFormatter setDateFormat:@"'Yesterday', MMMM d'Sth' h:mm"];
formatterPeriod = [[NSDateFormatter alloc] init];
[formatterPeriod setDateFormat:@"a"];
}
NSString *dateString;
if ([date compare:midnight] == NSOrderedDescending) {
dateString = [NSString stringWithFormat:@"%@%@",
[todayFormatter stringFromDate:date],
[[formatterPeriod stringFromDate:date] lowercaseString]];
} else if ([date compare:yesterday] == NSOrderedDescending) {
dateString = [NSString stringWithFormat:@"%@%@",
[yesterdayFormatter stringFromDate:date],
[[formatterPeriod stringFromDate:date] lowercaseString]];
} else {
dateString = [NSString stringWithFormat:@"%@%@",
[dateFormatter stringFromDate:date],
[[formatterPeriod stringFromDate:date] lowercaseString]];
}
dateString = [dateString stringByReplacingOccurrencesOfString:@"Sth"
withString:[Utilities suffixForDayInDate:date]];
return dateString;
}
+ (NSString *)formatShortDateFromTimestamp:(NSInteger)timestamp {
if (!timestamp) timestamp = [[NSDate date] timeIntervalSince1970];
NSDate *date = [NSDate dateWithTimeIntervalSince1970:(double)timestamp];
static NSDateFormatter *dateFormatter = nil;
static NSDateFormatter *todayFormatter = nil;
static NSDateFormatter *yesterdayFormatter = nil;
static NSDateFormatter *formatterPeriod = nil;
NSDate *today = [NSDate date];
NSDateComponents *components = [[NSCalendar currentCalendar]
components:NSIntegerMax
fromDate:today];
[components setHour:0];
[components setMinute:0];
[components setSecond:0];
NSDate *midnight = [[NSCalendar currentCalendar] dateFromComponents:components];
NSDate *yesterday = [NSDate dateWithTimeInterval:-60*60*24 sinceDate:midnight];
if (!dateFormatter || !todayFormatter || !yesterdayFormatter || !formatterPeriod) {
dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"dd LLL y, h:mm"];
todayFormatter = [[NSDateFormatter alloc] init];
[todayFormatter setDateFormat:@"h:mm"];
yesterdayFormatter = [[NSDateFormatter alloc] init];
[yesterdayFormatter setDateFormat:@"'Yesterday', h:mm"];
formatterPeriod = [[NSDateFormatter alloc] init];
[formatterPeriod setDateFormat:@"a"];
}
NSString *dateString;
if ([date compare:midnight] == NSOrderedDescending) {
dateString = [NSString stringWithFormat:@"%@%@",
[todayFormatter stringFromDate:date],
[[formatterPeriod stringFromDate:date] lowercaseString]];
} else if ([date compare:yesterday] == NSOrderedDescending) {
dateString = [NSString stringWithFormat:@"%@%@",
[yesterdayFormatter stringFromDate:date],
[[formatterPeriod stringFromDate:date] lowercaseString]];
} else {
dateString = [NSString stringWithFormat:@"%@%@",
[dateFormatter stringFromDate:date],
[[formatterPeriod stringFromDate:date] lowercaseString]];
}
return dateString;
}
+ (NSString *)suffixForDayInDate:(NSDate *)date {
NSInteger day = [[[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] components:NSDayCalendarUnit fromDate:date] day];
if (day == 11) {
return @"th";
} else if (day % 10 == 1) {
return @"st";
} else if (day % 10 == 2) {
return @"nd";
} else if (day % 10 == 3) {
return @"rd";
} else {
return @"th";
}
}
@end @end

View file

@ -49,6 +49,7 @@
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[appDelegate.feedsViewController showDoneNotifier]; [appDelegate.feedsViewController showDoneNotifier];
[appDelegate.feedsViewController hideNotifier]; [appDelegate.feedsViewController hideNotifier];
[appDelegate cleanImageCache];
}); });
return NO; return NO;
} }
@ -119,6 +120,8 @@
[cursor objectForColumnName:@"story_hash"], [cursor objectForColumnName:@"story_hash"],
[cursor objectForColumnName:@"story_timestamp"]]]; [cursor objectForColumnName:@"story_timestamp"]]];
} }
[cursor close];
[self updateProgress]; [self updateProgress];
}]; }];

View file

@ -61,8 +61,6 @@
} }
}); });
return NO; return NO;
} else {
NSLog(@"Fetching Stories: %@", [hashes objectAtIndex:0]);
} }
__block NSCondition *lock = [NSCondition new]; __block NSCondition *lock = [NSCondition new];
@ -74,7 +72,6 @@
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) { success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
[self storeAllUnreadStories:JSON withHashes:hashes]; [self storeAllUnreadStories:JSON withHashes:hashes];
NSLog(@"Done Storing Stories: %@", [hashes objectAtIndex:0]);
[lock signal]; [lock signal];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) { } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(@"Failed fetch all unreads."); NSLog(@"Failed fetch all unreads.");
@ -89,7 +86,6 @@
[lock waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:30]]; [lock waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:30]];
[lock unlock]; [lock unlock];
NSLog(@"Completed Fetching Stories: %@", [hashes objectAtIndex:0]);
return YES; return YES;
} }
@ -121,6 +117,7 @@
[hashes addObject:[cursor objectForColumnName:@"story_hash"]]; [hashes addObject:[cursor objectForColumnName:@"story_hash"]];
} }
[cursor close];
[self updateProgress]; [self updateProgress];
}]; }];
@ -141,14 +138,13 @@
(float)appDelegate.totalUnfetchedStoryCount); (float)appDelegate.totalUnfetchedStoryCount);
} }
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"appDelegate.remainingUnfetchedStoryCount %d (%f)", appDelegate.remainingUnfetchedStoryCount, progress); // NSLog(@"appDelegate.remainingUnfetchedStoryCount %d (%f)", appDelegate.remainingUnfetchedStoryCount, progress);
[appDelegate.feedsViewController showSyncingNotifier:progress hoursBack:hours]; [appDelegate.feedsViewController showSyncingNotifier:progress hoursBack:hours];
}); });
} }
- (void)storeAllUnreadStories:(NSDictionary *)results withHashes:(NSArray *)hashes { - (void)storeAllUnreadStories:(NSDictionary *)results withHashes:(NSArray *)hashes {
NSMutableArray *storyHashes = [hashes mutableCopy]; NSMutableArray *storyHashes = [hashes mutableCopy];
NSLog(@"storing hashes: %@", [storyHashes objectAtIndex:0]);
[appDelegate.database inDatabase:^(FMDatabase *db) { [appDelegate.database inDatabase:^(FMDatabase *db) {
BOOL anyInserted = NO; BOOL anyInserted = NO;
for (NSDictionary *story in [results objectForKey:@"stories"]) { for (NSDictionary *story in [results objectForKey:@"stories"]) {
@ -194,19 +190,24 @@
} }
if (anyInserted) { if (anyInserted) {
appDelegate.latestFetchedStoryDate = [[[[results objectForKey:@"stories"] lastObject] NSDictionary *lastStory;
objectForKey:@"story_timestamp"] intValue]; if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"default_order"]
isEqualToString:@"oldest"]) {
lastStory = [[results objectForKey:@"stories"] firstObject];
} else {
lastStory = [[results objectForKey:@"stories"] lastObject];
}
appDelegate.latestFetchedStoryDate = [[lastStory
objectForKey:@"story_timestamp"]
intValue];
} }
if ([storyHashes count]) { if ([storyHashes count]) {
NSLog(@"Failed to fetch stories: %@", storyHashes); NSLog(@"Failed to fetch stories: %@", storyHashes);
[db executeUpdate:[NSString stringWithFormat:@"DELETE FROM unread_hashes WHERE story_hash IN (\"%@\")", [db executeUpdate:[NSString stringWithFormat:@"DELETE FROM unread_hashes WHERE story_hash IN (\"%@\")",
[storyHashes componentsJoinedByString:@"\",\" "]]]; [storyHashes componentsJoinedByString:@"\",\" "]]];
} }
NSLog(@"Done inserting stories (in transaction)");
}]; }];
NSLog(@"Done inserting stories");
[appDelegate storeUserProfiles:[results objectForKey:@"user_profiles"]]; [appDelegate storeUserProfiles:[results objectForKey:@"user_profiles"]];
} }

View file

@ -66,29 +66,38 @@
]; ];
} }
} }
}]; }];
[appDelegate.database inTransaction:^(FMDatabase *db, BOOL *rollback) { [appDelegate.database inTransaction:^(FMDatabase *db, BOOL *rollback) {
// Once all unread hashes are in, only keep under preference for offline limit // Once all unread hashes are in, only keep under preference for offline limit
NSInteger offlineLimit = [[NSUserDefaults standardUserDefaults] integerForKey:@"offline_store_limit"]; NSInteger offlineLimit = [[NSUserDefaults standardUserDefaults]
integerForKey:@"offline_store_limit"];
NSString *order; NSString *order;
NSString *orderComp; NSString *orderComp;
if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"default_order"] isEqualToString:@"oldest"]) { if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"default_order"]
isEqualToString:@"oldest"]) {
order = @"ASC"; order = @"ASC";
orderComp = @">"; orderComp = @">";
} else { } else {
order = @"DESC"; order = @"DESC";
orderComp = @"<"; orderComp = @"<";
} }
FMResultSet *cursor = [db executeQuery:[NSString stringWithFormat:@"SELECT story_timestamp FROM unread_hashes ORDER BY story_timestamp %@ LIMIT 1 OFFSET %d", order, offlineLimit]]; NSString *lastStorySql = [NSString stringWithFormat:
@"SELECT story_timestamp FROM unread_hashes "
"ORDER BY story_timestamp %@ LIMIT 1 OFFSET %ld",
order, (long)offlineLimit];
FMResultSet *cursor = [db executeQuery:lastStorySql];
int offlineLimitTimestamp = 0; int offlineLimitTimestamp = 0;
while ([cursor next]) { while ([cursor next]) {
offlineLimitTimestamp = [cursor intForColumn:@"story_timestamp"]; offlineLimitTimestamp = [cursor intForColumn:@"story_timestamp"];
break; break;
} }
NSLog(@"Deleting stories over limit: %d - %d", offlineLimit, offlineLimitTimestamp); [cursor close];
[db executeUpdate:[NSString stringWithFormat:@"DELETE FROM unread_hashes WHERE story_timestamp %@ %d", orderComp, offlineLimitTimestamp]];
[db executeUpdate:[NSString stringWithFormat:@"DELETE FROM stories WHERE story_timestamp %@ %d", orderComp, offlineLimitTimestamp]]; if (offlineLimitTimestamp) {
NSLog(@"Deleting stories over limit: %ld - %d", (long)offlineLimit, offlineLimitTimestamp);
[db executeUpdate:[NSString stringWithFormat:@"DELETE FROM unread_hashes WHERE story_timestamp %@ %d", orderComp, offlineLimitTimestamp]];
[db executeUpdate:[NSString stringWithFormat:@"DELETE FROM stories WHERE story_timestamp %@ %d", orderComp, offlineLimitTimestamp]];
}
}]; }];
appDelegate.totalUnfetchedStoryCount = 0; appDelegate.totalUnfetchedStoryCount = 0;

View file

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>application-identifier</key>
<string>$(AppIdentifierPrefix)$(CFBundleIdentifier)</string>
<key>get-task-allow</key>
<false/>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)$(CFBundleIdentifier)</string>
</array>
</dict>
</plist>

View file

@ -9,35 +9,20 @@
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string> <string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key> <key>CFBundleIconFile</key>
<string>logo_57.png</string> <string>logo_120.png</string>
<key>CFBundleIconFiles</key> <key>CFBundleIcons~ipad</key>
<array>
<string>logo_144.png</string>
<string>logo_72.png</string>
<string>logo_57.png</string>
<string>logo_114.png</string>
<string>Default-Portrait@2x~ipad.png</string>
<string>Default-Landscape@2x~ipad.png</string>
<string>Default-Portrait~ipad.png</string>
<string>Default-Landscape~ipad.png</string>
</array>
<key>CFBundleIcons</key>
<dict> <dict>
<key>CFBundlePrimaryIcon</key> <key>CFBundlePrimaryIcon</key>
<dict> <dict>
<key>CFBundleIconFiles</key> <key>CFBundleIconFiles</key>
<array> <array>
<string>logo_144.png</string> <string>logo_58</string>
<string>logo_72.png</string> <string>logo_29</string>
<string>logo_57.png</string> <string>logo_40</string>
<string>logo_114.png</string> <string>logo_80</string>
<string>Default-Portrait@2x~ipad.png</string> <string>logo_152</string>
<string>Default-Landscape@2x~ipad.png</string> <string>logo_76</string>
<string>Default-Portrait~ipad.png</string>
<string>Default-Landscape~ipad.png</string>
</array> </array>
<key>UIPrerenderedIcon</key>
<true/>
</dict> </dict>
</dict> </dict>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
@ -49,7 +34,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>3.0.1</string> <string>3.5</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleURLTypes</key> <key>CFBundleURLTypes</key>
@ -78,7 +63,7 @@
</dict> </dict>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>3.0.1</string> <string>3.5</string>
<key>FacebookAppID</key> <key>FacebookAppID</key>
<string>230426707030569</string> <string>230426707030569</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
@ -87,8 +72,136 @@
<string>MainWindow</string> <string>MainWindow</string>
<key>NSMainNibFile~ipad</key> <key>NSMainNibFile~ipad</key>
<string>MainWindow~ipad</string> <string>MainWindow~ipad</string>
<key>UILaunchImages</key>
<array>
<dict>
<key>UILaunchImageMinimumOSVersion</key>
<string>7.0</string>
<key>UILaunchImageName</key>
<string>Default</string>
<key>UILaunchImageOrientation</key>
<string>Portrait</string>
<key>UILaunchImageSize</key>
<string>{320, 480}</string>
</dict>
<dict>
<key>UILaunchImageMinimumOSVersion</key>
<string>7.0</string>
<key>UILaunchImageName</key>
<string>Default</string>
<key>UILaunchImageOrientation</key>
<string>Portrait</string>
<key>UILaunchImageSize</key>
<string>{320, 568}</string>
</dict>
<dict>
<key>UILaunchImageMinimumOSVersion</key>
<string>7.0</string>
<key>UILaunchImageName</key>
<string>Default</string>
<key>UILaunchImageOrientation</key>
<string>Portrait</string>
<key>UILaunchImageSize</key>
<string>{320, 480}</string>
</dict>
<dict>
<key>UILaunchImageMinimumOSVersion</key>
<string>7.0</string>
<key>UILaunchImageName</key>
<string>launch_iphone_tall</string>
<key>UILaunchImageOrientation</key>
<string>Portrait</string>
<key>UILaunchImageSize</key>
<string>{320, 568}</string>
</dict>
<dict>
<key>UILaunchImageMinimumOSVersion</key>
<string>7.0</string>
<key>UILaunchImageName</key>
<string>launch_iphone</string>
<key>UILaunchImageOrientation</key>
<string>Portrait</string>
<key>UILaunchImageSize</key>
<string>{320, 480}</string>
</dict>
</array>
<key>UILaunchImages~ipad</key>
<array>
<dict>
<key>UILaunchImageMinimumOSVersion</key>
<string>7.0</string>
<key>UILaunchImageName</key>
<string>Default-landscape</string>
<key>UILaunchImageOrientation</key>
<string>Landscape</string>
<key>UILaunchImageSize</key>
<string>{768, 1024}</string>
</dict>
<dict>
<key>UILaunchImageMinimumOSVersion</key>
<string>7.0</string>
<key>UILaunchImageName</key>
<string>Default-portrait</string>
<key>UILaunchImageOrientation</key>
<string>Portrait</string>
<key>UILaunchImageSize</key>
<string>{768, 1024}</string>
</dict>
<dict>
<key>UILaunchImageMinimumOSVersion</key>
<string>7.0</string>
<key>UILaunchImageName</key>
<string>Default-portrait</string>
<key>UILaunchImageOrientation</key>
<string>Portrait</string>
<key>UILaunchImageSize</key>
<string>{768, 1024}</string>
</dict>
<dict>
<key>UILaunchImageMinimumOSVersion</key>
<string>7.0</string>
<key>UILaunchImageName</key>
<string>launch_ipad_landscape</string>
<key>UILaunchImageOrientation</key>
<string>Landscape</string>
<key>UILaunchImageSize</key>
<string>{768, 1024}</string>
</dict>
<dict>
<key>UILaunchImageMinimumOSVersion</key>
<string>7.0</string>
<key>UILaunchImageName</key>
<string>launch_ipad_portrait</string>
<key>UILaunchImageOrientation</key>
<string>Portrait</string>
<key>UILaunchImageSize</key>
<string>{768, 1024}</string>
</dict>
<dict>
<key>UILaunchImageMinimumOSVersion</key>
<string>7.0</string>
<key>UILaunchImageName</key>
<string>launch_iphone_tall</string>
<key>UILaunchImageOrientation</key>
<string>Portrait</string>
<key>UILaunchImageSize</key>
<string>{320, 568}</string>
</dict>
<dict>
<key>UILaunchImageMinimumOSVersion</key>
<string>7.0</string>
<key>UILaunchImageName</key>
<string>launch_iphone</string>
<key>UILaunchImageOrientation</key>
<string>Portrait</string>
<key>UILaunchImageSize</key>
<string>{320, 480}</string>
</dict>
</array>
<key>UIPrerenderedIcon</key> <key>UIPrerenderedIcon</key>
<true/> <true/>
<key>UIStatusBarHidden</key>
<false/>
<key>UIStatusBarStyle</key> <key>UIStatusBarStyle</key>
<string>UIStatusBarStyleBlackOpaque</string> <string>UIStatusBarStyleBlackOpaque</string>
<key>UISupportedInterfaceOrientations</key> <key>UISupportedInterfaceOrientations</key>

Binary file not shown.

View file

@ -11,7 +11,7 @@
<key>kind</key> <key>kind</key>
<string>software-package</string> <string>software-package</string>
<key>url</key> <key>url</key>
<string>http://www.newsblur.com/ios/NewsBlur.ipa</string> <string>http://dev.newsblur.com/ios/NewsBlur.ipa</string>
</dict> </dict>
<dict> <dict>
<key>kind</key> <key>kind</key>
@ -19,7 +19,7 @@
<key>needs-shine</key> <key>needs-shine</key>
<false/> <false/>
<key>url</key> <key>url</key>
<string>http://www.newsblur.com/media/ios/Resources/logo_512.png</string> <string>http://www.newsblur.com/media/ios/Resources/logos/logo_512.png</string>
</dict> </dict>
<dict> <dict>
<key>kind</key> <key>kind</key>
@ -27,7 +27,7 @@
<key>needs-shine</key> <key>needs-shine</key>
<false/> <false/>
<key>url</key> <key>url</key>
<string>http://www.newsblur.com/media/ios/Resources/logo_57.png</string> <string>http://www.newsblur.com/media/ios/Resources/logos/logo_58.png</string>
</dict> </dict>
</array> </array>
<key>metadata</key> <key>metadata</key>
@ -35,7 +35,7 @@
<key>bundle-identifier</key> <key>bundle-identifier</key>
<string>com.newsblur.NewsBlur</string> <string>com.newsblur.NewsBlur</string>
<key>bundle-version</key> <key>bundle-version</key>
<string>3.0.1</string> <string>3.0.4</string>
<key>kind</key> <key>kind</key>
<string>software</string> <string>software</string>
<key>title</key> <key>title</key>

View file

@ -51,16 +51,16 @@
438FEDE815D5B15F00E3B3C9 /* FollowGrid.m in Sources */ = {isa = PBXBuildFile; fileRef = 438FEDE715D5B15F00E3B3C9 /* FollowGrid.m */; }; 438FEDE815D5B15F00E3B3C9 /* FollowGrid.m in Sources */ = {isa = PBXBuildFile; fileRef = 438FEDE715D5B15F00E3B3C9 /* FollowGrid.m */; };
439DAB201590DA350019B0EB /* FeedsMenuViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 439DAB1E1590DA350019B0EB /* FeedsMenuViewController.m */; }; 439DAB201590DA350019B0EB /* FeedsMenuViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 439DAB1E1590DA350019B0EB /* FeedsMenuViewController.m */; };
439DAB211590DA350019B0EB /* FeedsMenuViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 439DAB1F1590DA350019B0EB /* FeedsMenuViewController.xib */; }; 439DAB211590DA350019B0EB /* FeedsMenuViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 439DAB1F1590DA350019B0EB /* FeedsMenuViewController.xib */; };
43A3914415B73A7B0074B212 /* AFHTTPClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A3913015B73A7B0074B212 /* AFHTTPClient.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 43A3914415B73A7B0074B212 /* AFHTTPClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A3913015B73A7B0074B212 /* AFHTTPClient.m */; };
43A3914515B73A7B0074B212 /* AFHTTPRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A3913215B73A7B0074B212 /* AFHTTPRequestOperation.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 43A3914515B73A7B0074B212 /* AFHTTPRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A3913215B73A7B0074B212 /* AFHTTPRequestOperation.m */; };
43A3914615B73A7B0074B212 /* AFImageRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A3913415B73A7B0074B212 /* AFImageRequestOperation.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 43A3914615B73A7B0074B212 /* AFImageRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A3913415B73A7B0074B212 /* AFImageRequestOperation.m */; };
43A3914715B73A7B0074B212 /* AFJSONRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A3913615B73A7B0074B212 /* AFJSONRequestOperation.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 43A3914715B73A7B0074B212 /* AFJSONRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A3913615B73A7B0074B212 /* AFJSONRequestOperation.m */; };
43A3914815B73A7B0074B212 /* AFJSONUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A3913815B73A7B0074B212 /* AFJSONUtilities.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 43A3914815B73A7B0074B212 /* AFJSONUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A3913815B73A7B0074B212 /* AFJSONUtilities.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
43A3914915B73A7B0074B212 /* AFNetworkActivityIndicatorManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A3913A15B73A7B0074B212 /* AFNetworkActivityIndicatorManager.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 43A3914915B73A7B0074B212 /* AFNetworkActivityIndicatorManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A3913A15B73A7B0074B212 /* AFNetworkActivityIndicatorManager.m */; };
43A3914A15B73A7B0074B212 /* AFPropertyListRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A3913D15B73A7B0074B212 /* AFPropertyListRequestOperation.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 43A3914A15B73A7B0074B212 /* AFPropertyListRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A3913D15B73A7B0074B212 /* AFPropertyListRequestOperation.m */; };
43A3914B15B73A7B0074B212 /* AFURLConnectionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A3913F15B73A7B0074B212 /* AFURLConnectionOperation.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 43A3914B15B73A7B0074B212 /* AFURLConnectionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A3913F15B73A7B0074B212 /* AFURLConnectionOperation.m */; };
43A3914C15B73A7B0074B212 /* AFXMLRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A3914115B73A7B0074B212 /* AFXMLRequestOperation.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 43A3914C15B73A7B0074B212 /* AFXMLRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A3914115B73A7B0074B212 /* AFXMLRequestOperation.m */; };
43A3914D15B73A7B0074B212 /* UIImageView+AFNetworking.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A3914315B73A7B0074B212 /* UIImageView+AFNetworking.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 43A3914D15B73A7B0074B212 /* UIImageView+AFNetworking.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A3914315B73A7B0074B212 /* UIImageView+AFNetworking.m */; };
43A4BAC815C8663600F3B8D4 /* UIBarButtonItem+WEPopover.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A4BAC015C8663600F3B8D4 /* UIBarButtonItem+WEPopover.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 43A4BAC815C8663600F3B8D4 /* UIBarButtonItem+WEPopover.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A4BAC015C8663600F3B8D4 /* UIBarButtonItem+WEPopover.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
43A4BAC915C8663600F3B8D4 /* WEPopoverContainerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A4BAC215C8663600F3B8D4 /* WEPopoverContainerView.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 43A4BAC915C8663600F3B8D4 /* WEPopoverContainerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A4BAC215C8663600F3B8D4 /* WEPopoverContainerView.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
43A4BACA15C8663600F3B8D4 /* WEPopoverController.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A4BAC415C8663600F3B8D4 /* WEPopoverController.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 43A4BACA15C8663600F3B8D4 /* WEPopoverController.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A4BAC415C8663600F3B8D4 /* WEPopoverController.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
@ -95,31 +95,14 @@
43A4C44F15B00A26008787B5 /* arrow@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C3F415B00A26008787B5 /* arrow@2x.png */; }; 43A4C44F15B00A26008787B5 /* arrow@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C3F415B00A26008787B5 /* arrow@2x.png */; };
43A4C45215B00A26008787B5 /* Background.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C3F715B00A26008787B5 /* Background.png */; }; 43A4C45215B00A26008787B5 /* Background.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C3F715B00A26008787B5 /* Background.png */; };
43A4C45315B00A26008787B5 /* Background@2X.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C3F815B00A26008787B5 /* Background@2X.png */; }; 43A4C45315B00A26008787B5 /* Background@2X.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C3F815B00A26008787B5 /* Background@2X.png */; };
43A4C45B15B00A26008787B5 /* Default-Landscape.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C40015B00A26008787B5 /* Default-Landscape.png */; };
43A4C45C15B00A26008787B5 /* Default-Landscape@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C40115B00A26008787B5 /* Default-Landscape@2x.png */; };
43A4C45D15B00A26008787B5 /* Default-Landscape@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C40215B00A26008787B5 /* Default-Landscape@2x~ipad.png */; };
43A4C45E15B00A26008787B5 /* Default-Landscape~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C40315B00A26008787B5 /* Default-Landscape~ipad.png */; };
43A4C45F15B00A26008787B5 /* Default-Portrait.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C40415B00A26008787B5 /* Default-Portrait.png */; };
43A4C46015B00A26008787B5 /* Default-Portrait@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C40515B00A26008787B5 /* Default-Portrait@2x.png */; };
43A4C46115B00A26008787B5 /* Default-Portrait@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C40615B00A26008787B5 /* Default-Portrait@2x~ipad.png */; };
43A4C46215B00A26008787B5 /* Default-Portrait~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C40715B00A26008787B5 /* Default-Portrait~ipad.png */; };
43A4C46315B00A26008787B5 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C40815B00A26008787B5 /* Default.png */; };
43A4C46415B00A26008787B5 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C40915B00A26008787B5 /* Default@2x.png */; };
43A4C46615B00A26008787B5 /* disclosure.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C40B15B00A26008787B5 /* disclosure.png */; }; 43A4C46615B00A26008787B5 /* disclosure.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C40B15B00A26008787B5 /* disclosure.png */; };
43A4C46B15B00A26008787B5 /* feeds_background.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C41015B00A26008787B5 /* feeds_background.png */; };
43A4C46C15B00A26008787B5 /* fleuron.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C41115B00A26008787B5 /* fleuron.png */; }; 43A4C46C15B00A26008787B5 /* fleuron.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C41115B00A26008787B5 /* fleuron.png */; };
43A4C47A15B00A26008787B5 /* logo_57.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C41F15B00A26008787B5 /* logo_57.png */; };
43A4C47B15B00A26008787B5 /* logo_72.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C42015B00A26008787B5 /* logo_72.png */; };
43A4C47C15B00A26008787B5 /* logo_114.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C42115B00A26008787B5 /* logo_114.png */; };
43A4C47D15B00A26008787B5 /* logo_144.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C42215B00A26008787B5 /* logo_144.png */; };
43A4C47E15B00A26008787B5 /* logo_512.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C42315B00A26008787B5 /* logo_512.png */; }; 43A4C47E15B00A26008787B5 /* logo_512.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C42315B00A26008787B5 /* logo_512.png */; };
43A4C47F15B00A26008787B5 /* logo_background.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C42415B00A26008787B5 /* logo_background.png */; }; 43A4C47F15B00A26008787B5 /* logo_background.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C42415B00A26008787B5 /* logo_background.png */; };
43A4C48015B00A26008787B5 /* logo_newsblur_512.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C42515B00A26008787B5 /* logo_newsblur_512.png */; };
43A4C48115B00A26008787B5 /* logo_newsblur_blur.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C42615B00A26008787B5 /* logo_newsblur_blur.png */; }; 43A4C48115B00A26008787B5 /* logo_newsblur_blur.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C42615B00A26008787B5 /* logo_newsblur_blur.png */; };
43A4C49A15B00A26008787B5 /* warning.gif in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C43F15B00A26008787B5 /* warning.gif */; }; 43A4C49A15B00A26008787B5 /* warning.gif in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C43F15B00A26008787B5 /* warning.gif */; };
43A4C49B15B00A26008787B5 /* warning.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C44015B00A26008787B5 /* warning.png */; }; 43A4C49B15B00A26008787B5 /* warning.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C44015B00A26008787B5 /* warning.png */; };
43A4C49C15B00A26008787B5 /* world.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C44115B00A26008787B5 /* world.png */; }; 43A4C49C15B00A26008787B5 /* world.png in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C44115B00A26008787B5 /* world.png */; };
43A4C49E15B00CD3008787B5 /* Entitlements.entitlements in Resources */ = {isa = PBXBuildFile; fileRef = 43A4C49D15B00CD3008787B5 /* Entitlements.entitlements */; };
43ABBCAA15B53A1400EA3111 /* InteractionCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 43ABBCA915B53A1400EA3111 /* InteractionCell.m */; }; 43ABBCAA15B53A1400EA3111 /* InteractionCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 43ABBCA915B53A1400EA3111 /* InteractionCell.m */; };
43AF417715C30B1600758366 /* 37x-Checkmark.png in Resources */ = {isa = PBXBuildFile; fileRef = 43AF417515C30B1600758366 /* 37x-Checkmark.png */; }; 43AF417715C30B1600758366 /* 37x-Checkmark.png in Resources */ = {isa = PBXBuildFile; fileRef = 43AF417515C30B1600758366 /* 37x-Checkmark.png */; };
43AF417815C30B1600758366 /* 37x-Checkmark@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 43AF417615C30B1600758366 /* 37x-Checkmark@2x.png */; }; 43AF417815C30B1600758366 /* 37x-Checkmark@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 43AF417615C30B1600758366 /* 37x-Checkmark@2x.png */; };
@ -147,10 +130,8 @@
43C1680B15B3D99B00428BA3 /* 7-location-place.png in Resources */ = {isa = PBXBuildFile; fileRef = 43C1680A15B3D99B00428BA3 /* 7-location-place.png */; }; 43C1680B15B3D99B00428BA3 /* 7-location-place.png in Resources */ = {isa = PBXBuildFile; fileRef = 43C1680A15B3D99B00428BA3 /* 7-location-place.png */; };
43C3D40415D44EA30066D36D /* user_light.png in Resources */ = {isa = PBXBuildFile; fileRef = 43C3D40215D44EA30066D36D /* user_light.png */; }; 43C3D40415D44EA30066D36D /* user_light.png in Resources */ = {isa = PBXBuildFile; fileRef = 43C3D40215D44EA30066D36D /* user_light.png */; };
43C3D40515D44EA30066D36D /* user_light@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 43C3D40315D44EA30066D36D /* user_light@2x.png */; }; 43C3D40515D44EA30066D36D /* user_light@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 43C3D40315D44EA30066D36D /* user_light@2x.png */; };
43C3D40815D4680C0066D36D /* green_focus.png in Resources */ = {isa = PBXBuildFile; fileRef = 43C3D40715D4680C0066D36D /* green_focus.png */; };
43C3D40A15D468BA0066D36D /* all.png in Resources */ = {isa = PBXBuildFile; fileRef = 43C3D40915D468BA0066D36D /* all.png */; }; 43C3D40A15D468BA0066D36D /* all.png in Resources */ = {isa = PBXBuildFile; fileRef = 43C3D40915D468BA0066D36D /* all.png */; };
43C3D40C15D469010066D36D /* unread_yellow.png in Resources */ = {isa = PBXBuildFile; fileRef = 43C3D40B15D469010066D36D /* unread_yellow.png */; }; 43C3D40C15D469010066D36D /* unread_yellow.png in Resources */ = {isa = PBXBuildFile; fileRef = 43C3D40B15D469010066D36D /* unread_yellow.png */; };
43C3D41015D46D2B0066D36D /* green_focus@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 43C3D40F15D46D2B0066D36D /* green_focus@2x.png */; };
43C3D41215D46D330066D36D /* all@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 43C3D41115D46D330066D36D /* all@2x.png */; }; 43C3D41215D46D330066D36D /* all@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 43C3D41115D46D330066D36D /* all@2x.png */; };
43C95C49158BEC450086C69B /* GoogleReaderViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 43C95C47158BEC440086C69B /* GoogleReaderViewController.xib */; }; 43C95C49158BEC450086C69B /* GoogleReaderViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 43C95C47158BEC440086C69B /* GoogleReaderViewController.xib */; };
43CE0F5F15DADB7F00608ED8 /* SiteCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 43CE0F5E15DADB7F00608ED8 /* SiteCell.m */; }; 43CE0F5F15DADB7F00608ED8 /* SiteCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 43CE0F5E15DADB7F00608ED8 /* SiteCell.m */; };
@ -236,16 +217,8 @@
FF4151C416DEDF9D0013E84B /* markread@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FF4151C216DEDF9D0013E84B /* markread@2x.png */; }; FF4151C416DEDF9D0013E84B /* markread@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FF4151C216DEDF9D0013E84B /* markread@2x.png */; };
FF4151C716DEF1A80013E84B /* original_button.png in Resources */ = {isa = PBXBuildFile; fileRef = FF4151C516DEF1A80013E84B /* original_button.png */; }; FF4151C716DEF1A80013E84B /* original_button.png in Resources */ = {isa = PBXBuildFile; fileRef = FF4151C516DEF1A80013E84B /* original_button.png */; };
FF4151C816DEF1A80013E84B /* original_button@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FF4151C616DEF1A80013E84B /* original_button@2x.png */; }; FF4151C816DEF1A80013E84B /* original_button@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FF4151C616DEF1A80013E84B /* original_button@2x.png */; };
FF4151E916DEF9960013E84B /* back_button_background.png in Resources */ = {isa = PBXBuildFile; fileRef = FF4151E116DEF9960013E84B /* back_button_background.png */; }; FF468E3817FCFB970080325C /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF468E3717FCFB970080325C /* AVFoundation.framework */; };
FF4151EA16DEF9960013E84B /* back_button_background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FF4151E216DEF9960013E84B /* back_button_background@2x.png */; };
FF4151EB16DEF9960013E84B /* back_button_landscape_background.png in Resources */ = {isa = PBXBuildFile; fileRef = FF4151E316DEF9960013E84B /* back_button_landscape_background.png */; };
FF4151EC16DEF9960013E84B /* back_button_landscape_background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FF4151E416DEF9960013E84B /* back_button_landscape_background@2x.png */; };
FF4151ED16DEF9960013E84B /* back_button_landscape_selected_background.png in Resources */ = {isa = PBXBuildFile; fileRef = FF4151E516DEF9960013E84B /* back_button_landscape_selected_background.png */; };
FF4151EE16DEF9960013E84B /* back_button_landscape_selected_background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FF4151E616DEF9960013E84B /* back_button_landscape_selected_background@2x.png */; };
FF4151EF16DEF9960013E84B /* back_button_selected_background.png in Resources */ = {isa = PBXBuildFile; fileRef = FF4151E716DEF9960013E84B /* back_button_selected_background.png */; };
FF4151F016DEF9960013E84B /* back_button_selected_background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FF4151E816DEF9960013E84B /* back_button_selected_background@2x.png */; };
FF4EE9A4175EC9CF005891B5 /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FF4EE9A3175EC9CF005891B5 /* libsqlite3.dylib */; }; FF4EE9A4175EC9CF005891B5 /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FF4EE9A3175EC9CF005891B5 /* libsqlite3.dylib */; };
FF546DF71602930100948020 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FF546DF61602930100948020 /* Default-568h@2x.png */; };
FF546DF9160298E500948020 /* fleuron@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FF546DF8160298E500948020 /* fleuron@2x.png */; }; FF546DF9160298E500948020 /* fleuron@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FF546DF8160298E500948020 /* fleuron@2x.png */; };
FF5D3FFE1799F53C00349659 /* VUPinboardAccess.m in Sources */ = {isa = PBXBuildFile; fileRef = FF5D3FEB1799F53C00349659 /* VUPinboardAccess.m */; }; FF5D3FFE1799F53C00349659 /* VUPinboardAccess.m in Sources */ = {isa = PBXBuildFile; fileRef = FF5D3FEB1799F53C00349659 /* VUPinboardAccess.m */; };
FF5D3FFF1799F53C00349659 /* VUPinboardActivity.m in Sources */ = {isa = PBXBuildFile; fileRef = FF5D3FED1799F53C00349659 /* VUPinboardActivity.m */; }; FF5D3FFF1799F53C00349659 /* VUPinboardActivity.m in Sources */ = {isa = PBXBuildFile; fileRef = FF5D3FED1799F53C00349659 /* VUPinboardActivity.m */; };
@ -276,7 +249,6 @@
FF6618C8176184560039913B /* NBNotifier.m in Sources */ = {isa = PBXBuildFile; fileRef = FF6618C7176184560039913B /* NBNotifier.m */; }; FF6618C8176184560039913B /* NBNotifier.m in Sources */ = {isa = PBXBuildFile; fileRef = FF6618C7176184560039913B /* NBNotifier.m */; };
FF67D3B2168924C40057A7DA /* TrainerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FF67D3B1168924C40057A7DA /* TrainerViewController.m */; }; FF67D3B2168924C40057A7DA /* TrainerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FF67D3B1168924C40057A7DA /* TrainerViewController.m */; };
FF67D3B7168977690057A7DA /* TrainerViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = FF67D3B6168977690057A7DA /* TrainerViewController.xib */; }; FF67D3B7168977690057A7DA /* TrainerViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = FF67D3B6168977690057A7DA /* TrainerViewController.xib */; };
FF67D3B916897AD80057A7DA /* TrainerViewController~ipad.xib in Resources */ = {isa = PBXBuildFile; fileRef = FF67D3B816897AD80057A7DA /* TrainerViewController~ipad.xib */; };
FF67D3BB168A70630057A7DA /* trainer.css in Resources */ = {isa = PBXBuildFile; fileRef = FF67D3BA168A70630057A7DA /* trainer.css */; }; FF67D3BB168A70630057A7DA /* trainer.css in Resources */ = {isa = PBXBuildFile; fileRef = FF67D3BA168A70630057A7DA /* trainer.css */; };
FF67D3C1168A708D0057A7DA /* storyDetailView.css in Resources */ = {isa = PBXBuildFile; fileRef = FF67D3BD168A708D0057A7DA /* storyDetailView.css */; }; FF67D3C1168A708D0057A7DA /* storyDetailView.css in Resources */ = {isa = PBXBuildFile; fileRef = FF67D3BD168A708D0057A7DA /* storyDetailView.css */; };
FF67D3CC168A73380057A7DA /* storyDetailView.js in Resources */ = {isa = PBXBuildFile; fileRef = FF67D3BE168A708D0057A7DA /* storyDetailView.js */; }; FF67D3CC168A73380057A7DA /* storyDetailView.js in Resources */ = {isa = PBXBuildFile; fileRef = FF67D3BE168A708D0057A7DA /* storyDetailView.js */; };
@ -317,6 +289,9 @@
FF85BF7116D6A90D002D334D /* ak-icon-global.png in Resources */ = {isa = PBXBuildFile; fileRef = FF85BF7016D6A90D002D334D /* ak-icon-global.png */; }; FF85BF7116D6A90D002D334D /* ak-icon-global.png in Resources */ = {isa = PBXBuildFile; fileRef = FF85BF7016D6A90D002D334D /* ak-icon-global.png */; };
FF85BF7416D6A972002D334D /* ak-icon-allstories.png in Resources */ = {isa = PBXBuildFile; fileRef = FF85BF7216D6A972002D334D /* ak-icon-allstories.png */; }; FF85BF7416D6A972002D334D /* ak-icon-allstories.png in Resources */ = {isa = PBXBuildFile; fileRef = FF85BF7216D6A972002D334D /* ak-icon-allstories.png */; };
FF85BF7516D6A972002D334D /* ak-icon-blurblogs.png in Resources */ = {isa = PBXBuildFile; fileRef = FF85BF7316D6A972002D334D /* ak-icon-blurblogs.png */; }; FF85BF7516D6A972002D334D /* ak-icon-blurblogs.png in Resources */ = {isa = PBXBuildFile; fileRef = FF85BF7316D6A972002D334D /* ak-icon-blurblogs.png */; };
FF88F10D1811BAEC007FEE78 /* unread_green@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FF88F10B1811BAEC007FEE78 /* unread_green@2x.png */; };
FF88F10E1811BAEC007FEE78 /* unread_green.png in Resources */ = {isa = PBXBuildFile; fileRef = FF88F10C1811BAEC007FEE78 /* unread_green.png */; };
FF9B8BB217F2351A0036A41C /* NBBarButtonItem.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9B8BB117F2351A0036A41C /* NBBarButtonItem.m */; };
FFAD4971144A386100BA6919 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FFAD4970144A386100BA6919 /* libz.dylib */; }; FFAD4971144A386100BA6919 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FFAD4970144A386100BA6919 /* libz.dylib */; };
FFAF53661799D18B00C7FCCB /* RWInstapaperActivity.m in Sources */ = {isa = PBXBuildFile; fileRef = FFAF53461799D18B00C7FCCB /* RWInstapaperActivity.m */; }; FFAF53661799D18B00C7FCCB /* RWInstapaperActivity.m in Sources */ = {isa = PBXBuildFile; fileRef = FFAF53461799D18B00C7FCCB /* RWInstapaperActivity.m */; };
FFAF53671799D18B00C7FCCB /* RWInstapaperActivityRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = FFAF53481799D18B00C7FCCB /* RWInstapaperActivityRequest.m */; }; FFAF53671799D18B00C7FCCB /* RWInstapaperActivityRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = FFAF53481799D18B00C7FCCB /* RWInstapaperActivityRequest.m */; };
@ -347,6 +322,13 @@
FFB5F50B17187B6F00C8B432 /* big_world.png in Resources */ = {isa = PBXBuildFile; fileRef = FFB5F50A17187B6F00C8B432 /* big_world.png */; }; FFB5F50B17187B6F00C8B432 /* big_world.png in Resources */ = {isa = PBXBuildFile; fileRef = FFB5F50A17187B6F00C8B432 /* big_world.png */; };
FFB757FE1727098D001D132F /* menu_icn_mail.png in Resources */ = {isa = PBXBuildFile; fileRef = FFB757FC1727098D001D132F /* menu_icn_mail.png */; }; FFB757FE1727098D001D132F /* menu_icn_mail.png in Resources */ = {isa = PBXBuildFile; fileRef = FFB757FC1727098D001D132F /* menu_icn_mail.png */; };
FFB757FF1727098D001D132F /* menu_icn_mail@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFB757FD1727098D001D132F /* menu_icn_mail@2x.png */; }; FFB757FF1727098D001D132F /* menu_icn_mail@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFB757FD1727098D001D132F /* menu_icn_mail@2x.png */; };
FFB9BE4717F4B65B00FE0A36 /* logo_120.png in Resources */ = {isa = PBXBuildFile; fileRef = FFB9BE4017F4B65B00FE0A36 /* logo_120.png */; };
FFB9BE4817F4B65B00FE0A36 /* logo_152.png in Resources */ = {isa = PBXBuildFile; fileRef = FFB9BE4117F4B65B00FE0A36 /* logo_152.png */; };
FFB9BE4917F4B65B00FE0A36 /* logo_29.png in Resources */ = {isa = PBXBuildFile; fileRef = FFB9BE4217F4B65B00FE0A36 /* logo_29.png */; };
FFB9BE4A17F4B65B00FE0A36 /* logo_40.png in Resources */ = {isa = PBXBuildFile; fileRef = FFB9BE4317F4B65B00FE0A36 /* logo_40.png */; };
FFB9BE4B17F4B65B00FE0A36 /* logo_58.png in Resources */ = {isa = PBXBuildFile; fileRef = FFB9BE4417F4B65B00FE0A36 /* logo_58.png */; };
FFB9BE4C17F4B65B00FE0A36 /* logo_76.png in Resources */ = {isa = PBXBuildFile; fileRef = FFB9BE4517F4B65B00FE0A36 /* logo_76.png */; };
FFB9BE4D17F4B65B00FE0A36 /* logo_80.png in Resources */ = {isa = PBXBuildFile; fileRef = FFB9BE4617F4B65B00FE0A36 /* logo_80.png */; };
FFC518B91768E59F00542719 /* g_icn_offline.png in Resources */ = {isa = PBXBuildFile; fileRef = FFC518B81768E59F00542719 /* g_icn_offline.png */; }; FFC518B91768E59F00542719 /* g_icn_offline.png in Resources */ = {isa = PBXBuildFile; fileRef = FFC518B81768E59F00542719 /* g_icn_offline.png */; };
FFC5F30B16E2D2C2007AC72C /* story_share_appnet_active.png in Resources */ = {isa = PBXBuildFile; fileRef = FFC5F2FF16E2D2C2007AC72C /* story_share_appnet_active.png */; }; FFC5F30B16E2D2C2007AC72C /* story_share_appnet_active.png in Resources */ = {isa = PBXBuildFile; fileRef = FFC5F2FF16E2D2C2007AC72C /* story_share_appnet_active.png */; };
FFC5F30C16E2D2C2007AC72C /* story_share_appnet_active@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFC5F30016E2D2C2007AC72C /* story_share_appnet_active@2x.png */; }; FFC5F30C16E2D2C2007AC72C /* story_share_appnet_active@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFC5F30016E2D2C2007AC72C /* story_share_appnet_active@2x.png */; };
@ -360,21 +342,16 @@
FFC5F31416E2D2C2007AC72C /* story_share_twitter_active@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFC5F30816E2D2C2007AC72C /* story_share_twitter_active@2x.png */; }; FFC5F31416E2D2C2007AC72C /* story_share_twitter_active@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFC5F30816E2D2C2007AC72C /* story_share_twitter_active@2x.png */; };
FFC5F31516E2D2C2007AC72C /* story_share_twitter.png in Resources */ = {isa = PBXBuildFile; fileRef = FFC5F30916E2D2C2007AC72C /* story_share_twitter.png */; }; FFC5F31516E2D2C2007AC72C /* story_share_twitter.png in Resources */ = {isa = PBXBuildFile; fileRef = FFC5F30916E2D2C2007AC72C /* story_share_twitter.png */; };
FFC5F31616E2D2C2007AC72C /* story_share_twitter@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFC5F30A16E2D2C2007AC72C /* story_share_twitter@2x.png */; }; FFC5F31616E2D2C2007AC72C /* story_share_twitter@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFC5F30A16E2D2C2007AC72C /* story_share_twitter@2x.png */; };
FFC5F31B16E2E9FB007AC72C /* toolbar_button_landscape_selected.png in Resources */ = {isa = PBXBuildFile; fileRef = FFC5F31716E2E9FB007AC72C /* toolbar_button_landscape_selected.png */; };
FFC5F31C16E2E9FB007AC72C /* toolbar_button_landscape.png in Resources */ = {isa = PBXBuildFile; fileRef = FFC5F31816E2E9FB007AC72C /* toolbar_button_landscape.png */; };
FFC5F31D16E2E9FB007AC72C /* toolbar_button_landscape@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFC5F31916E2E9FB007AC72C /* toolbar_button_landscape@2x.png */; };
FFC5F31E16E2E9FB007AC72C /* toolbar_button_selected_landscape@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFC5F31A16E2E9FB007AC72C /* toolbar_button_selected_landscape@2x.png */; };
FFC5F32016E2F24B007AC72C /* white_spacer.png in Resources */ = {isa = PBXBuildFile; fileRef = FFC5F31F16E2F24B007AC72C /* white_spacer.png */; }; FFC5F32016E2F24B007AC72C /* white_spacer.png in Resources */ = {isa = PBXBuildFile; fileRef = FFC5F31F16E2F24B007AC72C /* white_spacer.png */; };
FFCF51A316E020DD008C7C42 /* toolbar_background.png in Resources */ = {isa = PBXBuildFile; fileRef = FFCF51A116E020DD008C7C42 /* toolbar_background.png */; }; FFCDD8F317F4BCB4000C6483 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFCDD8ED17F4BCB4000C6483 /* Default-568h@2x.png */; };
FFCF51A416E020DD008C7C42 /* toolbar_background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFCF51A216E020DD008C7C42 /* toolbar_background@2x.png */; }; FFCDD8F417F4BCB4000C6483 /* Default-landscape.png in Resources */ = {isa = PBXBuildFile; fileRef = FFCDD8EE17F4BCB4000C6483 /* Default-landscape.png */; };
FFCF51A716E028B0008C7C42 /* navbar_background.png in Resources */ = {isa = PBXBuildFile; fileRef = FFCF51A516E028B0008C7C42 /* navbar_background.png */; }; FFCDD8F517F4BCB4000C6483 /* Default-landscape@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFCDD8EF17F4BCB4000C6483 /* Default-landscape@2x.png */; };
FFCF51A816E028B0008C7C42 /* navbar_background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFCF51A616E028B0008C7C42 /* navbar_background@2x.png */; }; FFCDD8F617F4BCB4000C6483 /* Default-portrait.png in Resources */ = {isa = PBXBuildFile; fileRef = FFCDD8F017F4BCB4000C6483 /* Default-portrait.png */; };
FFCF51AB16E029E6008C7C42 /* navbar_landscape_background.png in Resources */ = {isa = PBXBuildFile; fileRef = FFCF51A916E029E6008C7C42 /* navbar_landscape_background.png */; }; FFCDD8F717F4BCB4000C6483 /* Default-portrait@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFCDD8F117F4BCB4000C6483 /* Default-portrait@2x.png */; };
FFCF51AC16E029E6008C7C42 /* navbar_landscape_background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFCF51AA16E029E6008C7C42 /* navbar_landscape_background@2x.png */; }; FFCDD8F817F4BCB4000C6483 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = FFCDD8F217F4BCB4000C6483 /* Default.png */; };
FFCF51C516E0300F008C7C42 /* button_selected.png in Resources */ = {isa = PBXBuildFile; fileRef = FFCF51C116E0300F008C7C42 /* button_selected.png */; }; FFCDD8FA17F50C08000C6483 /* drag_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = FFCDD8F917F50C08000C6483 /* drag_icon.png */; };
FFCF51C616E0300F008C7C42 /* button_selected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFCF51C216E0300F008C7C42 /* button_selected@2x.png */; }; FFCDD8FE17F6368F000C6483 /* MCSwipeTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = FFCDD8FD17F6368F000C6483 /* MCSwipeTableViewCell.m */; };
FFCF51C716E0300F008C7C42 /* button.png in Resources */ = {isa = PBXBuildFile; fileRef = FFCF51C316E0300F008C7C42 /* button.png */; }; FFCDD90117F65A71000C6483 /* NBSwipeableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = FFCDD90017F65A71000C6483 /* NBSwipeableCell.m */; };
FFCF51C816E0300F008C7C42 /* button@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFCF51C416E0300F008C7C42 /* button@2x.png */; };
FFD1D7311459B63500E46F89 /* BaseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FFD1D7301459B63500E46F89 /* BaseViewController.m */; }; FFD1D7311459B63500E46F89 /* BaseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FFD1D7301459B63500E46F89 /* BaseViewController.m */; };
FFD887F01445F1E800385399 /* AddSiteAutocompleteCell.m in Sources */ = {isa = PBXBuildFile; fileRef = FFD887EE1445F1E800385399 /* AddSiteAutocompleteCell.m */; }; FFD887F01445F1E800385399 /* AddSiteAutocompleteCell.m in Sources */ = {isa = PBXBuildFile; fileRef = FFD887EE1445F1E800385399 /* AddSiteAutocompleteCell.m */; };
FFDCA0AF16E80866000D8E0C /* DEComposeRuledView.m in Sources */ = {isa = PBXBuildFile; fileRef = FFDCA0A516E80866000D8E0C /* DEComposeRuledView.m */; }; FFDCA0AF16E80866000D8E0C /* DEComposeRuledView.m in Sources */ = {isa = PBXBuildFile; fileRef = FFDCA0A516E80866000D8E0C /* DEComposeRuledView.m */; };
@ -430,20 +407,20 @@
FFE816AD17E29D71008AF4B0 /* big_world_white.png in Resources */ = {isa = PBXBuildFile; fileRef = FFE816AC17E29D71008AF4B0 /* big_world_white.png */; }; FFE816AD17E29D71008AF4B0 /* big_world_white.png in Resources */ = {isa = PBXBuildFile; fileRef = FFE816AC17E29D71008AF4B0 /* big_world_white.png */; };
FFECD019172B105800D45A62 /* UIActivitySafari.png in Resources */ = {isa = PBXBuildFile; fileRef = FFECD017172B105800D45A62 /* UIActivitySafari.png */; }; FFECD019172B105800D45A62 /* UIActivitySafari.png in Resources */ = {isa = PBXBuildFile; fileRef = FFECD017172B105800D45A62 /* UIActivitySafari.png */; };
FFECD01A172B105800D45A62 /* UIActivitySafari@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFECD018172B105800D45A62 /* UIActivitySafari@2x.png */; }; FFECD01A172B105800D45A62 /* UIActivitySafari@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFECD018172B105800D45A62 /* UIActivitySafari@2x.png */; };
FFF1E4B9177504CA00BF59D3 /* IASKAppSettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E49B177504CA00BF59D3 /* IASKAppSettingsViewController.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; FFF1E4B9177504CA00BF59D3 /* IASKAppSettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E49B177504CA00BF59D3 /* IASKAppSettingsViewController.m */; };
FFF1E4BA177504CA00BF59D3 /* IASKAppSettingsWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E49D177504CA00BF59D3 /* IASKAppSettingsWebViewController.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; FFF1E4BA177504CA00BF59D3 /* IASKAppSettingsWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E49D177504CA00BF59D3 /* IASKAppSettingsWebViewController.m */; };
FFF1E4BB177504CA00BF59D3 /* IASKSpecifierValuesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E49F177504CA00BF59D3 /* IASKSpecifierValuesViewController.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; FFF1E4BB177504CA00BF59D3 /* IASKSpecifierValuesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E49F177504CA00BF59D3 /* IASKSpecifierValuesViewController.m */; };
FFF1E4BC177504CA00BF59D3 /* IASKSettingsReader.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E4A3177504CA00BF59D3 /* IASKSettingsReader.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; FFF1E4BC177504CA00BF59D3 /* IASKSettingsReader.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E4A3177504CA00BF59D3 /* IASKSettingsReader.m */; };
FFF1E4BD177504CA00BF59D3 /* IASKSettingsStore.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E4A5177504CA00BF59D3 /* IASKSettingsStore.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; FFF1E4BD177504CA00BF59D3 /* IASKSettingsStore.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E4A5177504CA00BF59D3 /* IASKSettingsStore.m */; };
FFF1E4BE177504CA00BF59D3 /* IASKSettingsStoreFile.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E4A7177504CA00BF59D3 /* IASKSettingsStoreFile.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; FFF1E4BE177504CA00BF59D3 /* IASKSettingsStoreFile.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E4A7177504CA00BF59D3 /* IASKSettingsStoreFile.m */; };
FFF1E4BF177504CA00BF59D3 /* IASKSettingsStoreUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E4A9177504CA00BF59D3 /* IASKSettingsStoreUserDefaults.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; FFF1E4BF177504CA00BF59D3 /* IASKSettingsStoreUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E4A9177504CA00BF59D3 /* IASKSettingsStoreUserDefaults.m */; };
FFF1E4C0177504CA00BF59D3 /* IASKSpecifier.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E4AB177504CA00BF59D3 /* IASKSpecifier.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; FFF1E4C0177504CA00BF59D3 /* IASKSpecifier.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E4AB177504CA00BF59D3 /* IASKSpecifier.m */; };
FFF1E4C1177504CA00BF59D3 /* IASKPSSliderSpecifierViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E4AE177504CA00BF59D3 /* IASKPSSliderSpecifierViewCell.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; FFF1E4C1177504CA00BF59D3 /* IASKPSSliderSpecifierViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E4AE177504CA00BF59D3 /* IASKPSSliderSpecifierViewCell.m */; };
FFF1E4C2177504CA00BF59D3 /* IASKPSTextFieldSpecifierViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E4B0177504CA00BF59D3 /* IASKPSTextFieldSpecifierViewCell.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; FFF1E4C2177504CA00BF59D3 /* IASKPSTextFieldSpecifierViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E4B0177504CA00BF59D3 /* IASKPSTextFieldSpecifierViewCell.m */; };
FFF1E4C3177504CA00BF59D3 /* IASKPSTitleValueSpecifierViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E4B2177504CA00BF59D3 /* IASKPSTitleValueSpecifierViewCell.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; FFF1E4C3177504CA00BF59D3 /* IASKPSTitleValueSpecifierViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E4B2177504CA00BF59D3 /* IASKPSTitleValueSpecifierViewCell.m */; };
FFF1E4C4177504CA00BF59D3 /* IASKSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E4B4177504CA00BF59D3 /* IASKSlider.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; FFF1E4C4177504CA00BF59D3 /* IASKSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E4B4177504CA00BF59D3 /* IASKSlider.m */; };
FFF1E4C5177504CA00BF59D3 /* IASKSwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E4B6177504CA00BF59D3 /* IASKSwitch.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; FFF1E4C5177504CA00BF59D3 /* IASKSwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E4B6177504CA00BF59D3 /* IASKSwitch.m */; };
FFF1E4C6177504CA00BF59D3 /* IASKTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E4B8177504CA00BF59D3 /* IASKTextField.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; FFF1E4C6177504CA00BF59D3 /* IASKTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF1E4B8177504CA00BF59D3 /* IASKTextField.m */; };
FFF1E4C817750BDD00BF59D3 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = FFF1E4C717750BDD00BF59D3 /* Settings.bundle */; }; FFF1E4C817750BDD00BF59D3 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = FFF1E4C717750BDD00BF59D3 /* Settings.bundle */; };
FFF1E4CB17750D2C00BF59D3 /* menu_icn_preferences.png in Resources */ = {isa = PBXBuildFile; fileRef = FFF1E4C917750D2C00BF59D3 /* menu_icn_preferences.png */; }; FFF1E4CB17750D2C00BF59D3 /* menu_icn_preferences.png in Resources */ = {isa = PBXBuildFile; fileRef = FFF1E4C917750D2C00BF59D3 /* menu_icn_preferences.png */; };
FFF1E4CC17750D2C00BF59D3 /* menu_icn_preferences@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFF1E4CA17750D2C00BF59D3 /* menu_icn_preferences@2x.png */; }; FFF1E4CC17750D2C00BF59D3 /* menu_icn_preferences@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFF1E4CA17750D2C00BF59D3 /* menu_icn_preferences@2x.png */; };
@ -579,31 +556,14 @@
43A4C3F415B00A26008787B5 /* arrow@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "arrow@2x.png"; sourceTree = "<group>"; }; 43A4C3F415B00A26008787B5 /* arrow@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "arrow@2x.png"; sourceTree = "<group>"; };
43A4C3F715B00A26008787B5 /* Background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Background.png; sourceTree = "<group>"; }; 43A4C3F715B00A26008787B5 /* Background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Background.png; sourceTree = "<group>"; };
43A4C3F815B00A26008787B5 /* Background@2X.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Background@2X.png"; sourceTree = "<group>"; }; 43A4C3F815B00A26008787B5 /* Background@2X.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Background@2X.png"; sourceTree = "<group>"; };
43A4C40015B00A26008787B5 /* Default-Landscape.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-Landscape.png"; sourceTree = "<group>"; };
43A4C40115B00A26008787B5 /* Default-Landscape@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-Landscape@2x.png"; sourceTree = "<group>"; };
43A4C40215B00A26008787B5 /* Default-Landscape@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-Landscape@2x~ipad.png"; sourceTree = "<group>"; };
43A4C40315B00A26008787B5 /* Default-Landscape~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-Landscape~ipad.png"; sourceTree = "<group>"; };
43A4C40415B00A26008787B5 /* Default-Portrait.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-Portrait.png"; sourceTree = "<group>"; };
43A4C40515B00A26008787B5 /* Default-Portrait@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-Portrait@2x.png"; sourceTree = "<group>"; };
43A4C40615B00A26008787B5 /* Default-Portrait@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-Portrait@2x~ipad.png"; sourceTree = "<group>"; };
43A4C40715B00A26008787B5 /* Default-Portrait~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-Portrait~ipad.png"; sourceTree = "<group>"; };
43A4C40815B00A26008787B5 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = "<group>"; };
43A4C40915B00A26008787B5 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = "<group>"; };
43A4C40B15B00A26008787B5 /* disclosure.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = disclosure.png; sourceTree = "<group>"; }; 43A4C40B15B00A26008787B5 /* disclosure.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = disclosure.png; sourceTree = "<group>"; };
43A4C41015B00A26008787B5 /* feeds_background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = feeds_background.png; sourceTree = "<group>"; };
43A4C41115B00A26008787B5 /* fleuron.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = fleuron.png; sourceTree = "<group>"; }; 43A4C41115B00A26008787B5 /* fleuron.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = fleuron.png; sourceTree = "<group>"; };
43A4C41F15B00A26008787B5 /* logo_57.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo_57.png; sourceTree = "<group>"; };
43A4C42015B00A26008787B5 /* logo_72.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo_72.png; sourceTree = "<group>"; };
43A4C42115B00A26008787B5 /* logo_114.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo_114.png; sourceTree = "<group>"; };
43A4C42215B00A26008787B5 /* logo_144.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo_144.png; sourceTree = "<group>"; };
43A4C42315B00A26008787B5 /* logo_512.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo_512.png; sourceTree = "<group>"; }; 43A4C42315B00A26008787B5 /* logo_512.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo_512.png; sourceTree = "<group>"; };
43A4C42415B00A26008787B5 /* logo_background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo_background.png; sourceTree = "<group>"; }; 43A4C42415B00A26008787B5 /* logo_background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo_background.png; sourceTree = "<group>"; };
43A4C42515B00A26008787B5 /* logo_newsblur_512.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo_newsblur_512.png; sourceTree = "<group>"; };
43A4C42615B00A26008787B5 /* logo_newsblur_blur.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo_newsblur_blur.png; sourceTree = "<group>"; }; 43A4C42615B00A26008787B5 /* logo_newsblur_blur.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo_newsblur_blur.png; sourceTree = "<group>"; };
43A4C43F15B00A26008787B5 /* warning.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = warning.gif; sourceTree = "<group>"; }; 43A4C43F15B00A26008787B5 /* warning.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = warning.gif; sourceTree = "<group>"; };
43A4C44015B00A26008787B5 /* warning.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = warning.png; sourceTree = "<group>"; }; 43A4C44015B00A26008787B5 /* warning.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = warning.png; sourceTree = "<group>"; };
43A4C44115B00A26008787B5 /* world.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = world.png; sourceTree = "<group>"; }; 43A4C44115B00A26008787B5 /* world.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = world.png; sourceTree = "<group>"; };
43A4C49D15B00CD3008787B5 /* Entitlements.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = Entitlements.entitlements; sourceTree = "<group>"; };
43ABBCA815B53A1400EA3111 /* InteractionCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InteractionCell.h; sourceTree = "<group>"; }; 43ABBCA815B53A1400EA3111 /* InteractionCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InteractionCell.h; sourceTree = "<group>"; };
43ABBCA915B53A1400EA3111 /* InteractionCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InteractionCell.m; sourceTree = "<group>"; }; 43ABBCA915B53A1400EA3111 /* InteractionCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InteractionCell.m; sourceTree = "<group>"; };
43AF417515C30B1600758366 /* 37x-Checkmark.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "37x-Checkmark.png"; sourceTree = "<group>"; }; 43AF417515C30B1600758366 /* 37x-Checkmark.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "37x-Checkmark.png"; sourceTree = "<group>"; };
@ -633,10 +593,8 @@
43C1680A15B3D99B00428BA3 /* 7-location-place.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "7-location-place.png"; sourceTree = "<group>"; }; 43C1680A15B3D99B00428BA3 /* 7-location-place.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "7-location-place.png"; sourceTree = "<group>"; };
43C3D40215D44EA30066D36D /* user_light.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = user_light.png; sourceTree = "<group>"; }; 43C3D40215D44EA30066D36D /* user_light.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = user_light.png; sourceTree = "<group>"; };
43C3D40315D44EA30066D36D /* user_light@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "user_light@2x.png"; sourceTree = "<group>"; }; 43C3D40315D44EA30066D36D /* user_light@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "user_light@2x.png"; sourceTree = "<group>"; };
43C3D40715D4680C0066D36D /* green_focus.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = green_focus.png; sourceTree = "<group>"; };
43C3D40915D468BA0066D36D /* all.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = all.png; sourceTree = "<group>"; }; 43C3D40915D468BA0066D36D /* all.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = all.png; sourceTree = "<group>"; };
43C3D40B15D469010066D36D /* unread_yellow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = unread_yellow.png; sourceTree = "<group>"; }; 43C3D40B15D469010066D36D /* unread_yellow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = unread_yellow.png; sourceTree = "<group>"; };
43C3D40F15D46D2B0066D36D /* green_focus@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "green_focus@2x.png"; sourceTree = "<group>"; };
43C3D41115D46D330066D36D /* all@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "all@2x.png"; sourceTree = "<group>"; }; 43C3D41115D46D330066D36D /* all@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "all@2x.png"; sourceTree = "<group>"; };
43C95C47158BEC440086C69B /* GoogleReaderViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = GoogleReaderViewController.xib; path = Classes/GoogleReaderViewController.xib; sourceTree = "<group>"; }; 43C95C47158BEC440086C69B /* GoogleReaderViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = GoogleReaderViewController.xib; path = Classes/GoogleReaderViewController.xib; sourceTree = "<group>"; };
43CE0F5D15DADB7E00608ED8 /* SiteCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SiteCell.h; sourceTree = "<group>"; }; 43CE0F5D15DADB7E00608ED8 /* SiteCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SiteCell.h; sourceTree = "<group>"; };
@ -769,16 +727,8 @@
FF4151C216DEDF9D0013E84B /* markread@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "markread@2x.png"; sourceTree = "<group>"; }; FF4151C216DEDF9D0013E84B /* markread@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "markread@2x.png"; sourceTree = "<group>"; };
FF4151C516DEF1A80013E84B /* original_button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = original_button.png; sourceTree = "<group>"; }; FF4151C516DEF1A80013E84B /* original_button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = original_button.png; sourceTree = "<group>"; };
FF4151C616DEF1A80013E84B /* original_button@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "original_button@2x.png"; sourceTree = "<group>"; }; FF4151C616DEF1A80013E84B /* original_button@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "original_button@2x.png"; sourceTree = "<group>"; };
FF4151E116DEF9960013E84B /* back_button_background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = back_button_background.png; sourceTree = "<group>"; }; FF468E3717FCFB970080325C /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
FF4151E216DEF9960013E84B /* back_button_background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "back_button_background@2x.png"; sourceTree = "<group>"; };
FF4151E316DEF9960013E84B /* back_button_landscape_background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = back_button_landscape_background.png; sourceTree = "<group>"; };
FF4151E416DEF9960013E84B /* back_button_landscape_background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "back_button_landscape_background@2x.png"; sourceTree = "<group>"; };
FF4151E516DEF9960013E84B /* back_button_landscape_selected_background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = back_button_landscape_selected_background.png; sourceTree = "<group>"; };
FF4151E616DEF9960013E84B /* back_button_landscape_selected_background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "back_button_landscape_selected_background@2x.png"; sourceTree = "<group>"; };
FF4151E716DEF9960013E84B /* back_button_selected_background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = back_button_selected_background.png; sourceTree = "<group>"; };
FF4151E816DEF9960013E84B /* back_button_selected_background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "back_button_selected_background@2x.png"; sourceTree = "<group>"; };
FF4EE9A3175EC9CF005891B5 /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; }; FF4EE9A3175EC9CF005891B5 /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; };
FF546DF61602930100948020 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = "<group>"; };
FF546DF8160298E500948020 /* fleuron@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "fleuron@2x.png"; sourceTree = "<group>"; }; FF546DF8160298E500948020 /* fleuron@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "fleuron@2x.png"; sourceTree = "<group>"; };
FF5D3FEA1799F53C00349659 /* VUPinboardAccess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VUPinboardAccess.h; sourceTree = "<group>"; }; FF5D3FEA1799F53C00349659 /* VUPinboardAccess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VUPinboardAccess.h; sourceTree = "<group>"; };
FF5D3FEB1799F53C00349659 /* VUPinboardAccess.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VUPinboardAccess.m; sourceTree = "<group>"; }; FF5D3FEB1799F53C00349659 /* VUPinboardAccess.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VUPinboardAccess.m; sourceTree = "<group>"; };
@ -822,9 +772,8 @@
FF67D3B0168924C40057A7DA /* TrainerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrainerViewController.h; sourceTree = "<group>"; }; FF67D3B0168924C40057A7DA /* TrainerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrainerViewController.h; sourceTree = "<group>"; };
FF67D3B1168924C40057A7DA /* TrainerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TrainerViewController.m; sourceTree = "<group>"; }; FF67D3B1168924C40057A7DA /* TrainerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TrainerViewController.m; sourceTree = "<group>"; };
FF67D3B6168977690057A7DA /* TrainerViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TrainerViewController.xib; sourceTree = "<group>"; }; FF67D3B6168977690057A7DA /* TrainerViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TrainerViewController.xib; sourceTree = "<group>"; };
FF67D3B816897AD80057A7DA /* TrainerViewController~ipad.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = "TrainerViewController~ipad.xib"; path = "Resources-iPad/Classes/TrainerViewController~ipad.xib"; sourceTree = "<group>"; };
FF67D3BA168A70630057A7DA /* trainer.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; name = trainer.css; path = ../static/trainer.css; sourceTree = "<group>"; }; FF67D3BA168A70630057A7DA /* trainer.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; name = trainer.css; path = ../static/trainer.css; sourceTree = "<group>"; };
FF67D3BD168A708D0057A7DA /* storyDetailView.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; name = storyDetailView.css; path = ../static/storyDetailView.css; sourceTree = "<group>"; }; FF67D3BD168A708D0057A7DA /* storyDetailView.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; name = storyDetailView.css; path = ../static/storyDetailView.css; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.css; };
FF67D3BE168A708D0057A7DA /* storyDetailView.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = storyDetailView.js; path = ../static/storyDetailView.js; sourceTree = "<group>"; }; FF67D3BE168A708D0057A7DA /* storyDetailView.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = storyDetailView.js; path = ../static/storyDetailView.js; sourceTree = "<group>"; };
FF67D3BF168A708D0057A7DA /* zepto.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = zepto.js; path = ../static/zepto.js; sourceTree = "<group>"; }; FF67D3BF168A708D0057A7DA /* zepto.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = zepto.js; path = ../static/zepto.js; sourceTree = "<group>"; };
FF67D3C4168A71870057A7DA /* trainer.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = trainer.js; path = ../static/trainer.js; sourceTree = "<group>"; }; FF67D3C4168A71870057A7DA /* trainer.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = trainer.js; path = ../static/trainer.js; sourceTree = "<group>"; };
@ -875,6 +824,10 @@
FF85BF7016D6A90D002D334D /* ak-icon-global.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "ak-icon-global.png"; sourceTree = "<group>"; }; FF85BF7016D6A90D002D334D /* ak-icon-global.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "ak-icon-global.png"; sourceTree = "<group>"; };
FF85BF7216D6A972002D334D /* ak-icon-allstories.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "ak-icon-allstories.png"; sourceTree = "<group>"; }; FF85BF7216D6A972002D334D /* ak-icon-allstories.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "ak-icon-allstories.png"; sourceTree = "<group>"; };
FF85BF7316D6A972002D334D /* ak-icon-blurblogs.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "ak-icon-blurblogs.png"; sourceTree = "<group>"; }; FF85BF7316D6A972002D334D /* ak-icon-blurblogs.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "ak-icon-blurblogs.png"; sourceTree = "<group>"; };
FF88F10B1811BAEC007FEE78 /* unread_green@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "unread_green@2x.png"; sourceTree = "<group>"; };
FF88F10C1811BAEC007FEE78 /* unread_green.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = unread_green.png; sourceTree = "<group>"; };
FF9B8BB017F2351A0036A41C /* NBBarButtonItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NBBarButtonItem.h; sourceTree = "<group>"; };
FF9B8BB117F2351A0036A41C /* NBBarButtonItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NBBarButtonItem.m; sourceTree = "<group>"; };
FFAD4970144A386100BA6919 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; FFAD4970144A386100BA6919 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
FFAF53451799D18B00C7FCCB /* RWInstapaperActivity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RWInstapaperActivity.h; sourceTree = "<group>"; }; FFAF53451799D18B00C7FCCB /* RWInstapaperActivity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RWInstapaperActivity.h; sourceTree = "<group>"; };
FFAF53461799D18B00C7FCCB /* RWInstapaperActivity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RWInstapaperActivity.m; sourceTree = "<group>"; }; FFAF53461799D18B00C7FCCB /* RWInstapaperActivity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RWInstapaperActivity.m; sourceTree = "<group>"; };
@ -938,6 +891,13 @@
FFB5F50A17187B6F00C8B432 /* big_world.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = big_world.png; sourceTree = "<group>"; }; FFB5F50A17187B6F00C8B432 /* big_world.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = big_world.png; sourceTree = "<group>"; };
FFB757FC1727098D001D132F /* menu_icn_mail.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu_icn_mail.png; sourceTree = "<group>"; }; FFB757FC1727098D001D132F /* menu_icn_mail.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu_icn_mail.png; sourceTree = "<group>"; };
FFB757FD1727098D001D132F /* menu_icn_mail@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "menu_icn_mail@2x.png"; sourceTree = "<group>"; }; FFB757FD1727098D001D132F /* menu_icn_mail@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "menu_icn_mail@2x.png"; sourceTree = "<group>"; };
FFB9BE4017F4B65B00FE0A36 /* logo_120.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo_120.png; sourceTree = "<group>"; };
FFB9BE4117F4B65B00FE0A36 /* logo_152.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo_152.png; sourceTree = "<group>"; };
FFB9BE4217F4B65B00FE0A36 /* logo_29.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo_29.png; sourceTree = "<group>"; };
FFB9BE4317F4B65B00FE0A36 /* logo_40.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo_40.png; sourceTree = "<group>"; };
FFB9BE4417F4B65B00FE0A36 /* logo_58.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo_58.png; sourceTree = "<group>"; };
FFB9BE4517F4B65B00FE0A36 /* logo_76.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo_76.png; sourceTree = "<group>"; };
FFB9BE4617F4B65B00FE0A36 /* logo_80.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo_80.png; sourceTree = "<group>"; };
FFC518B81768E59F00542719 /* g_icn_offline.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = g_icn_offline.png; sourceTree = "<group>"; }; FFC518B81768E59F00542719 /* g_icn_offline.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = g_icn_offline.png; sourceTree = "<group>"; };
FFC5F2FF16E2D2C2007AC72C /* story_share_appnet_active.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = story_share_appnet_active.png; sourceTree = "<group>"; }; FFC5F2FF16E2D2C2007AC72C /* story_share_appnet_active.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = story_share_appnet_active.png; sourceTree = "<group>"; };
FFC5F30016E2D2C2007AC72C /* story_share_appnet_active@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "story_share_appnet_active@2x.png"; sourceTree = "<group>"; }; FFC5F30016E2D2C2007AC72C /* story_share_appnet_active@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "story_share_appnet_active@2x.png"; sourceTree = "<group>"; };
@ -951,21 +911,18 @@
FFC5F30816E2D2C2007AC72C /* story_share_twitter_active@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "story_share_twitter_active@2x.png"; sourceTree = "<group>"; }; FFC5F30816E2D2C2007AC72C /* story_share_twitter_active@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "story_share_twitter_active@2x.png"; sourceTree = "<group>"; };
FFC5F30916E2D2C2007AC72C /* story_share_twitter.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = story_share_twitter.png; sourceTree = "<group>"; }; FFC5F30916E2D2C2007AC72C /* story_share_twitter.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = story_share_twitter.png; sourceTree = "<group>"; };
FFC5F30A16E2D2C2007AC72C /* story_share_twitter@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "story_share_twitter@2x.png"; sourceTree = "<group>"; }; FFC5F30A16E2D2C2007AC72C /* story_share_twitter@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "story_share_twitter@2x.png"; sourceTree = "<group>"; };
FFC5F31716E2E9FB007AC72C /* toolbar_button_landscape_selected.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = toolbar_button_landscape_selected.png; sourceTree = "<group>"; };
FFC5F31816E2E9FB007AC72C /* toolbar_button_landscape.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = toolbar_button_landscape.png; sourceTree = "<group>"; };
FFC5F31916E2E9FB007AC72C /* toolbar_button_landscape@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "toolbar_button_landscape@2x.png"; sourceTree = "<group>"; };
FFC5F31A16E2E9FB007AC72C /* toolbar_button_selected_landscape@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "toolbar_button_selected_landscape@2x.png"; sourceTree = "<group>"; };
FFC5F31F16E2F24B007AC72C /* white_spacer.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = white_spacer.png; sourceTree = "<group>"; }; FFC5F31F16E2F24B007AC72C /* white_spacer.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = white_spacer.png; sourceTree = "<group>"; };
FFCF51A116E020DD008C7C42 /* toolbar_background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = toolbar_background.png; sourceTree = "<group>"; }; FFCDD8ED17F4BCB4000C6483 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = "<group>"; };
FFCF51A216E020DD008C7C42 /* toolbar_background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "toolbar_background@2x.png"; sourceTree = "<group>"; }; FFCDD8EE17F4BCB4000C6483 /* Default-landscape.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-landscape.png"; sourceTree = "<group>"; };
FFCF51A516E028B0008C7C42 /* navbar_background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = navbar_background.png; sourceTree = "<group>"; }; FFCDD8EF17F4BCB4000C6483 /* Default-landscape@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-landscape@2x.png"; sourceTree = "<group>"; };
FFCF51A616E028B0008C7C42 /* navbar_background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "navbar_background@2x.png"; sourceTree = "<group>"; }; FFCDD8F017F4BCB4000C6483 /* Default-portrait.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-portrait.png"; sourceTree = "<group>"; };
FFCF51A916E029E6008C7C42 /* navbar_landscape_background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = navbar_landscape_background.png; sourceTree = "<group>"; }; FFCDD8F117F4BCB4000C6483 /* Default-portrait@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-portrait@2x.png"; sourceTree = "<group>"; };
FFCF51AA16E029E6008C7C42 /* navbar_landscape_background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "navbar_landscape_background@2x.png"; sourceTree = "<group>"; }; FFCDD8F217F4BCB4000C6483 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = "<group>"; };
FFCF51C116E0300F008C7C42 /* button_selected.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = button_selected.png; sourceTree = "<group>"; }; FFCDD8F917F50C08000C6483 /* drag_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = drag_icon.png; sourceTree = "<group>"; };
FFCF51C216E0300F008C7C42 /* button_selected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "button_selected@2x.png"; sourceTree = "<group>"; }; FFCDD8FC17F6368F000C6483 /* MCSwipeTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCSwipeTableViewCell.h; sourceTree = "<group>"; };
FFCF51C316E0300F008C7C42 /* button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = button.png; sourceTree = "<group>"; }; FFCDD8FD17F6368F000C6483 /* MCSwipeTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MCSwipeTableViewCell.m; sourceTree = "<group>"; };
FFCF51C416E0300F008C7C42 /* button@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "button@2x.png"; sourceTree = "<group>"; }; FFCDD8FF17F65A71000C6483 /* NBSwipeableCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NBSwipeableCell.h; sourceTree = "<group>"; };
FFCDD90017F65A71000C6483 /* NBSwipeableCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NBSwipeableCell.m; sourceTree = "<group>"; };
FFD1D72F1459B63500E46F89 /* BaseViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BaseViewController.h; sourceTree = "<group>"; }; FFD1D72F1459B63500E46F89 /* BaseViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BaseViewController.h; sourceTree = "<group>"; };
FFD1D7301459B63500E46F89 /* BaseViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BaseViewController.m; sourceTree = "<group>"; }; FFD1D7301459B63500E46F89 /* BaseViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BaseViewController.m; sourceTree = "<group>"; };
FFD887ED1445F1E800385399 /* AddSiteAutocompleteCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AddSiteAutocompleteCell.h; sourceTree = "<group>"; }; FFD887ED1445F1E800385399 /* AddSiteAutocompleteCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AddSiteAutocompleteCell.h; sourceTree = "<group>"; };
@ -1076,6 +1033,8 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
FF468E3817FCFB970080325C /* AVFoundation.framework in Frameworks */,
78095E45128EF37E00230C8E /* SystemConfiguration.framework in Frameworks */,
FF4EE9A4175EC9CF005891B5 /* libsqlite3.dylib in Frameworks */, FF4EE9A4175EC9CF005891B5 /* libsqlite3.dylib in Frameworks */,
FFDCA0C316E80952000D8E0C /* AdSupport.framework in Frameworks */, FFDCA0C316E80952000D8E0C /* AdSupport.framework in Frameworks */,
FFDCA0C116E8094F000D8E0C /* Accounts.framework in Frameworks */, FFDCA0C116E8094F000D8E0C /* Accounts.framework in Frameworks */,
@ -1091,7 +1050,6 @@
788EF356127E5BC80088EDC5 /* QuartzCore.framework in Frameworks */, 788EF356127E5BC80088EDC5 /* QuartzCore.framework in Frameworks */,
78095E3F128EF35400230C8E /* CFNetwork.framework in Frameworks */, 78095E3F128EF35400230C8E /* CFNetwork.framework in Frameworks */,
78095E43128EF37E00230C8E /* MobileCoreServices.framework in Frameworks */, 78095E43128EF37E00230C8E /* MobileCoreServices.framework in Frameworks */,
78095E45128EF37E00230C8E /* SystemConfiguration.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -1133,7 +1091,6 @@
29B97323FDCFA39411CA2CEA /* Frameworks */, 29B97323FDCFA39411CA2CEA /* Frameworks */,
19C28FACFE9D520D11CA2CBB /* Products */, 19C28FACFE9D520D11CA2CBB /* Products */,
8D1107310486CEB800E47090 /* NewsBlur-iPhone-Info.plist */, 8D1107310486CEB800E47090 /* NewsBlur-iPhone-Info.plist */,
43A4C49D15B00CD3008787B5 /* Entitlements.entitlements */,
); );
name = CustomTemplate; name = CustomTemplate;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1141,6 +1098,7 @@
29B97315FDCFA39411CA2CEA /* Other Sources */ = { 29B97315FDCFA39411CA2CEA /* Other Sources */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
FFCDD8FB17F6368F000C6483 /* MCSwipeTableViewCell */,
FF5D40091799F70200349659 /* ARChromeActivity */, FF5D40091799F70200349659 /* ARChromeActivity */,
FFAF53951799E69D00C7FCCB /* PocketSDK */, FFAF53951799E69D00C7FCCB /* PocketSDK */,
FFAF53A61799E69D00C7FCCB /* ReadabilityActivity */, FFAF53A61799E69D00C7FCCB /* ReadabilityActivity */,
@ -1184,6 +1142,7 @@
29B97323FDCFA39411CA2CEA /* Frameworks */ = { 29B97323FDCFA39411CA2CEA /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
FF468E3717FCFB970080325C /* AVFoundation.framework */,
FF4EE9A3175EC9CF005891B5 /* libsqlite3.dylib */, FF4EE9A3175EC9CF005891B5 /* libsqlite3.dylib */,
FFDCA0C216E80952000D8E0C /* AdSupport.framework */, FFDCA0C216E80952000D8E0C /* AdSupport.framework */,
FFDCA0C016E8094F000D8E0C /* Accounts.framework */, FFDCA0C016E8094F000D8E0C /* Accounts.framework */,
@ -1334,6 +1293,8 @@
431B857615A132B600DCE497 /* Images */ = { 431B857615A132B600DCE497 /* Images */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
FFCDD8F917F50C08000C6483 /* drag_icon.png */,
FFB9BE3F17F4B65B00FE0A36 /* logos */,
FFE816AC17E29D71008AF4B0 /* big_world_white.png */, FFE816AC17E29D71008AF4B0 /* big_world_white.png */,
FFE816AA17E280BD008AF4B0 /* ftux_tree.png */, FFE816AA17E280BD008AF4B0 /* ftux_tree.png */,
FF855B541794A53A0098D48A /* checkmark.png */, FF855B541794A53A0098D48A /* checkmark.png */,
@ -1403,10 +1364,6 @@
FF22FE4816E413C30046165A /* disclosure_border@2x.png */, FF22FE4816E413C30046165A /* disclosure_border@2x.png */,
FF22FE4916E413C30046165A /* disclosure@2x.png */, FF22FE4916E413C30046165A /* disclosure@2x.png */,
FFC5F31F16E2F24B007AC72C /* white_spacer.png */, FFC5F31F16E2F24B007AC72C /* white_spacer.png */,
FFC5F31716E2E9FB007AC72C /* toolbar_button_landscape_selected.png */,
FFC5F31816E2E9FB007AC72C /* toolbar_button_landscape.png */,
FFC5F31916E2E9FB007AC72C /* toolbar_button_landscape@2x.png */,
FFC5F31A16E2E9FB007AC72C /* toolbar_button_selected_landscape@2x.png */,
FFC5F2FF16E2D2C2007AC72C /* story_share_appnet_active.png */, FFC5F2FF16E2D2C2007AC72C /* story_share_appnet_active.png */,
FFC5F30016E2D2C2007AC72C /* story_share_appnet_active@2x.png */, FFC5F30016E2D2C2007AC72C /* story_share_appnet_active@2x.png */,
FFC5F30116E2D2C2007AC72C /* story_share_appnet.png */, FFC5F30116E2D2C2007AC72C /* story_share_appnet.png */,
@ -1419,24 +1376,6 @@
FFC5F30816E2D2C2007AC72C /* story_share_twitter_active@2x.png */, FFC5F30816E2D2C2007AC72C /* story_share_twitter_active@2x.png */,
FFC5F30916E2D2C2007AC72C /* story_share_twitter.png */, FFC5F30916E2D2C2007AC72C /* story_share_twitter.png */,
FFC5F30A16E2D2C2007AC72C /* story_share_twitter@2x.png */, FFC5F30A16E2D2C2007AC72C /* story_share_twitter@2x.png */,
FFCF51C116E0300F008C7C42 /* button_selected.png */,
FFCF51C216E0300F008C7C42 /* button_selected@2x.png */,
FFCF51C316E0300F008C7C42 /* button.png */,
FFCF51C416E0300F008C7C42 /* button@2x.png */,
FFCF51A916E029E6008C7C42 /* navbar_landscape_background.png */,
FFCF51AA16E029E6008C7C42 /* navbar_landscape_background@2x.png */,
FFCF51A516E028B0008C7C42 /* navbar_background.png */,
FFCF51A616E028B0008C7C42 /* navbar_background@2x.png */,
FFCF51A116E020DD008C7C42 /* toolbar_background.png */,
FFCF51A216E020DD008C7C42 /* toolbar_background@2x.png */,
FF4151E116DEF9960013E84B /* back_button_background.png */,
FF4151E216DEF9960013E84B /* back_button_background@2x.png */,
FF4151E316DEF9960013E84B /* back_button_landscape_background.png */,
FF4151E416DEF9960013E84B /* back_button_landscape_background@2x.png */,
FF4151E516DEF9960013E84B /* back_button_landscape_selected_background.png */,
FF4151E616DEF9960013E84B /* back_button_landscape_selected_background@2x.png */,
FF4151E716DEF9960013E84B /* back_button_selected_background.png */,
FF4151E816DEF9960013E84B /* back_button_selected_background@2x.png */,
FF4151C516DEF1A80013E84B /* original_button.png */, FF4151C516DEF1A80013E84B /* original_button.png */,
FF4151C616DEF1A80013E84B /* original_button@2x.png */, FF4151C616DEF1A80013E84B /* original_button@2x.png */,
FF4151C116DEDF9D0013E84B /* markread.png */, FF4151C116DEDF9D0013E84B /* markread.png */,
@ -1484,10 +1423,10 @@
43821AD215D8703F0034A4EF /* 258-checkmark@2x.png */, 43821AD215D8703F0034A4EF /* 258-checkmark@2x.png */,
43C3D40B15D469010066D36D /* unread_yellow.png */, 43C3D40B15D469010066D36D /* unread_yellow.png */,
FF29709316DD8CB000E92F85 /* unread_yellow@2x.png */, FF29709316DD8CB000E92F85 /* unread_yellow@2x.png */,
FF88F10B1811BAEC007FEE78 /* unread_green@2x.png */,
FF88F10C1811BAEC007FEE78 /* unread_green.png */,
43C3D40915D468BA0066D36D /* all.png */, 43C3D40915D468BA0066D36D /* all.png */,
43C3D41115D46D330066D36D /* all@2x.png */, 43C3D41115D46D330066D36D /* all@2x.png */,
43C3D40715D4680C0066D36D /* green_focus.png */,
43C3D40F15D46D2B0066D36D /* green_focus@2x.png */,
43C3D40215D44EA30066D36D /* user_light.png */, 43C3D40215D44EA30066D36D /* user_light.png */,
43C3D40315D44EA30066D36D /* user_light@2x.png */, 43C3D40315D44EA30066D36D /* user_light@2x.png */,
43A4BACC15C866FA00F3B8D4 /* popoverArrowDown.png */, 43A4BACC15C866FA00F3B8D4 /* popoverArrowDown.png */,
@ -1513,30 +1452,13 @@
43A4C3F415B00A26008787B5 /* arrow@2x.png */, 43A4C3F415B00A26008787B5 /* arrow@2x.png */,
43A4C3F715B00A26008787B5 /* Background.png */, 43A4C3F715B00A26008787B5 /* Background.png */,
43A4C3F815B00A26008787B5 /* Background@2X.png */, 43A4C3F815B00A26008787B5 /* Background@2X.png */,
43A4C40015B00A26008787B5 /* Default-Landscape.png */,
43A4C40115B00A26008787B5 /* Default-Landscape@2x.png */,
43A4C40215B00A26008787B5 /* Default-Landscape@2x~ipad.png */,
43A4C40315B00A26008787B5 /* Default-Landscape~ipad.png */,
43A4C40415B00A26008787B5 /* Default-Portrait.png */,
43A4C40515B00A26008787B5 /* Default-Portrait@2x.png */,
43A4C40615B00A26008787B5 /* Default-Portrait@2x~ipad.png */,
43A4C40715B00A26008787B5 /* Default-Portrait~ipad.png */,
FF546DF61602930100948020 /* Default-568h@2x.png */,
43A4C40815B00A26008787B5 /* Default.png */,
43A4C40915B00A26008787B5 /* Default@2x.png */,
43A4C40B15B00A26008787B5 /* disclosure.png */, 43A4C40B15B00A26008787B5 /* disclosure.png */,
43A4C41015B00A26008787B5 /* feeds_background.png */,
43A4C41115B00A26008787B5 /* fleuron.png */, 43A4C41115B00A26008787B5 /* fleuron.png */,
FF546DF8160298E500948020 /* fleuron@2x.png */, FF546DF8160298E500948020 /* fleuron@2x.png */,
43B6A26F15B6952F00CEA2E6 /* group.png */, 43B6A26F15B6952F00CEA2E6 /* group.png */,
43B6A27015B6952F00CEA2E6 /* group@2x.png */, 43B6A27015B6952F00CEA2E6 /* group@2x.png */,
43A4C41F15B00A26008787B5 /* logo_57.png */,
43A4C42015B00A26008787B5 /* logo_72.png */,
43A4C42115B00A26008787B5 /* logo_114.png */,
43A4C42215B00A26008787B5 /* logo_144.png */,
43A4C42315B00A26008787B5 /* logo_512.png */, 43A4C42315B00A26008787B5 /* logo_512.png */,
43A4C42415B00A26008787B5 /* logo_background.png */, 43A4C42415B00A26008787B5 /* logo_background.png */,
43A4C42515B00A26008787B5 /* logo_newsblur_512.png */,
43A4C42615B00A26008787B5 /* logo_newsblur_blur.png */, 43A4C42615B00A26008787B5 /* logo_newsblur_blur.png */,
43A4C43F15B00A26008787B5 /* warning.gif */, 43A4C43F15B00A26008787B5 /* warning.gif */,
43A4C44015B00A26008787B5 /* warning.png */, 43A4C44015B00A26008787B5 /* warning.png */,
@ -1682,7 +1604,6 @@
FF1660C916D6E9B400AF8541 /* DashboardViewController~ipad.xib */, FF1660C916D6E9B400AF8541 /* DashboardViewController~ipad.xib */,
43D0451F1565BC150085F811 /* MainWindow~ipad.xib */, 43D0451F1565BC150085F811 /* MainWindow~ipad.xib */,
43D045281565BC150085F811 /* MoveSiteViewController~ipad.xib */, 43D045281565BC150085F811 /* MoveSiteViewController~ipad.xib */,
FF67D3B816897AD80057A7DA /* TrainerViewController~ipad.xib */,
43D045221565BC150085F811 /* StoryDetailViewController~ipad.xib */, 43D045221565BC150085F811 /* StoryDetailViewController~ipad.xib */,
437AA8C9159394E2005463F5 /* ShareViewController~ipad.xib */, 437AA8C9159394E2005463F5 /* ShareViewController~ipad.xib */,
); );
@ -1763,6 +1684,10 @@
FF6618C7176184560039913B /* NBNotifier.m */, FF6618C7176184560039913B /* NBNotifier.m */,
FF11045D176950F900502C29 /* NBLoadingCell.h */, FF11045D176950F900502C29 /* NBLoadingCell.h */,
FF11045E176950F900502C29 /* NBLoadingCell.m */, FF11045E176950F900502C29 /* NBLoadingCell.m */,
FF9B8BB017F2351A0036A41C /* NBBarButtonItem.h */,
FF9B8BB117F2351A0036A41C /* NBBarButtonItem.m */,
FFCDD8FF17F65A71000C6483 /* NBSwipeableCell.h */,
FFCDD90017F65A71000C6483 /* NBSwipeableCell.m */,
); );
name = Foundation; name = Foundation;
sourceTree = "<group>"; sourceTree = "<group>";
@ -2008,6 +1933,36 @@
path = "Other Sources/ReadabilityActivity"; path = "Other Sources/ReadabilityActivity";
sourceTree = "<group>"; sourceTree = "<group>";
}; };
FFB9BE3F17F4B65B00FE0A36 /* logos */ = {
isa = PBXGroup;
children = (
FFCDD8ED17F4BCB4000C6483 /* Default-568h@2x.png */,
FFCDD8EE17F4BCB4000C6483 /* Default-landscape.png */,
FFCDD8EF17F4BCB4000C6483 /* Default-landscape@2x.png */,
FFCDD8F017F4BCB4000C6483 /* Default-portrait.png */,
FFCDD8F117F4BCB4000C6483 /* Default-portrait@2x.png */,
FFCDD8F217F4BCB4000C6483 /* Default.png */,
FFB9BE4017F4B65B00FE0A36 /* logo_120.png */,
FFB9BE4117F4B65B00FE0A36 /* logo_152.png */,
FFB9BE4217F4B65B00FE0A36 /* logo_29.png */,
FFB9BE4317F4B65B00FE0A36 /* logo_40.png */,
FFB9BE4417F4B65B00FE0A36 /* logo_58.png */,
FFB9BE4517F4B65B00FE0A36 /* logo_76.png */,
FFB9BE4617F4B65B00FE0A36 /* logo_80.png */,
);
path = logos;
sourceTree = "<group>";
};
FFCDD8FB17F6368F000C6483 /* MCSwipeTableViewCell */ = {
isa = PBXGroup;
children = (
FFCDD8FC17F6368F000C6483 /* MCSwipeTableViewCell.h */,
FFCDD8FD17F6368F000C6483 /* MCSwipeTableViewCell.m */,
);
name = MCSwipeTableViewCell;
path = "Other Sources/MCSwipeTableViewCell";
sourceTree = "<group>";
};
FFDCA0A316E80866000D8E0C /* REComposeViewController */ = { FFDCA0A316E80866000D8E0C /* REComposeViewController */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -2127,6 +2082,11 @@
attributes = { attributes = {
LastUpgradeCheck = 0500; LastUpgradeCheck = 0500;
ORGANIZATIONNAME = NewsBlur; ORGANIZATIONNAME = NewsBlur;
TargetAttributes = {
1D6058900D05DD3D006BFB54 = {
DevelopmentTeam = U92APKK285;
};
};
}; };
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "NewsBlur" */; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "NewsBlur" */;
compatibilityVersion = "Xcode 3.2"; compatibilityVersion = "Xcode 3.2";
@ -2200,36 +2160,21 @@
43763AD2158F90B100B3DBE2 /* FontSettingsViewController.xib in Resources */, 43763AD2158F90B100B3DBE2 /* FontSettingsViewController.xib in Resources */,
439DAB211590DA350019B0EB /* FeedsMenuViewController.xib in Resources */, 439DAB211590DA350019B0EB /* FeedsMenuViewController.xib in Resources */,
437AA8CB159394E2005463F5 /* ShareViewController~ipad.xib in Resources */, 437AA8CB159394E2005463F5 /* ShareViewController~ipad.xib in Resources */,
FF88F10D1811BAEC007FEE78 /* unread_green@2x.png in Resources */,
43081E2215AFE84200B24D7A /* ShareViewController.xib in Resources */, 43081E2215AFE84200B24D7A /* ShareViewController.xib in Resources */,
43A4C44E15B00A26008787B5 /* arrow.png in Resources */, 43A4C44E15B00A26008787B5 /* arrow.png in Resources */,
43A4C44F15B00A26008787B5 /* arrow@2x.png in Resources */, 43A4C44F15B00A26008787B5 /* arrow@2x.png in Resources */,
43A4C45215B00A26008787B5 /* Background.png in Resources */, 43A4C45215B00A26008787B5 /* Background.png in Resources */,
43A4C45315B00A26008787B5 /* Background@2X.png in Resources */, 43A4C45315B00A26008787B5 /* Background@2X.png in Resources */,
43A4C45B15B00A26008787B5 /* Default-Landscape.png in Resources */,
43A4C45C15B00A26008787B5 /* Default-Landscape@2x.png in Resources */,
43A4C45D15B00A26008787B5 /* Default-Landscape@2x~ipad.png in Resources */,
43A4C45E15B00A26008787B5 /* Default-Landscape~ipad.png in Resources */,
43A4C45F15B00A26008787B5 /* Default-Portrait.png in Resources */,
43A4C46015B00A26008787B5 /* Default-Portrait@2x.png in Resources */,
43A4C46115B00A26008787B5 /* Default-Portrait@2x~ipad.png in Resources */,
43A4C46215B00A26008787B5 /* Default-Portrait~ipad.png in Resources */,
43A4C46315B00A26008787B5 /* Default.png in Resources */,
43A4C46415B00A26008787B5 /* Default@2x.png in Resources */,
43A4C46615B00A26008787B5 /* disclosure.png in Resources */, 43A4C46615B00A26008787B5 /* disclosure.png in Resources */,
43A4C46B15B00A26008787B5 /* feeds_background.png in Resources */,
43A4C46C15B00A26008787B5 /* fleuron.png in Resources */, 43A4C46C15B00A26008787B5 /* fleuron.png in Resources */,
43A4C47A15B00A26008787B5 /* logo_57.png in Resources */,
43A4C47B15B00A26008787B5 /* logo_72.png in Resources */,
43A4C47C15B00A26008787B5 /* logo_114.png in Resources */,
43A4C47D15B00A26008787B5 /* logo_144.png in Resources */,
43A4C47E15B00A26008787B5 /* logo_512.png in Resources */, 43A4C47E15B00A26008787B5 /* logo_512.png in Resources */,
43A4C47F15B00A26008787B5 /* logo_background.png in Resources */, 43A4C47F15B00A26008787B5 /* logo_background.png in Resources */,
43A4C48015B00A26008787B5 /* logo_newsblur_512.png in Resources */, FFB9BE4717F4B65B00FE0A36 /* logo_120.png in Resources */,
43A4C48115B00A26008787B5 /* logo_newsblur_blur.png in Resources */, 43A4C48115B00A26008787B5 /* logo_newsblur_blur.png in Resources */,
43A4C49A15B00A26008787B5 /* warning.gif in Resources */, 43A4C49A15B00A26008787B5 /* warning.gif in Resources */,
43A4C49B15B00A26008787B5 /* warning.png in Resources */, 43A4C49B15B00A26008787B5 /* warning.png in Resources */,
43A4C49C15B00A26008787B5 /* world.png in Resources */, 43A4C49C15B00A26008787B5 /* world.png in Resources */,
43A4C49E15B00CD3008787B5 /* Entitlements.entitlements in Resources */,
43C1680B15B3D99B00428BA3 /* 7-location-place.png in Resources */, 43C1680B15B3D99B00428BA3 /* 7-location-place.png in Resources */,
43B6A27515B6952F00CEA2E6 /* group.png in Resources */, 43B6A27515B6952F00CEA2E6 /* group.png in Resources */,
43B6A27615B6952F00CEA2E6 /* group@2x.png in Resources */, 43B6A27615B6952F00CEA2E6 /* group@2x.png in Resources */,
@ -2242,6 +2187,7 @@
43A4BADC15C866FA00F3B8D4 /* popoverArrowDown@2x.png in Resources */, 43A4BADC15C866FA00F3B8D4 /* popoverArrowDown@2x.png in Resources */,
43A4BADD15C866FA00F3B8D4 /* popoverArrowDownSimple.png in Resources */, 43A4BADD15C866FA00F3B8D4 /* popoverArrowDownSimple.png in Resources */,
43A4BADE15C866FA00F3B8D4 /* popoverArrowLeft.png in Resources */, 43A4BADE15C866FA00F3B8D4 /* popoverArrowLeft.png in Resources */,
FFB9BE4817F4B65B00FE0A36 /* logo_152.png in Resources */,
43A4BADF15C866FA00F3B8D4 /* popoverArrowLeft@2x.png in Resources */, 43A4BADF15C866FA00F3B8D4 /* popoverArrowLeft@2x.png in Resources */,
43A4BAE015C866FA00F3B8D4 /* popoverArrowLeftSimple.png in Resources */, 43A4BAE015C866FA00F3B8D4 /* popoverArrowLeftSimple.png in Resources */,
43A4BAE115C866FA00F3B8D4 /* popoverArrowRight.png in Resources */, 43A4BAE115C866FA00F3B8D4 /* popoverArrowRight.png in Resources */,
@ -2252,18 +2198,18 @@
43A4BAE615C866FA00F3B8D4 /* popoverArrowUpSimple.png in Resources */, 43A4BAE615C866FA00F3B8D4 /* popoverArrowUpSimple.png in Resources */,
43A4BAE715C866FA00F3B8D4 /* popoverBg.png in Resources */, 43A4BAE715C866FA00F3B8D4 /* popoverBg.png in Resources */,
43A4BAE815C866FA00F3B8D4 /* popoverBg@2x.png in Resources */, 43A4BAE815C866FA00F3B8D4 /* popoverBg@2x.png in Resources */,
FF88F10E1811BAEC007FEE78 /* unread_green.png in Resources */,
43A4BAE915C866FA00F3B8D4 /* popoverBgSimple.png in Resources */, 43A4BAE915C866FA00F3B8D4 /* popoverBgSimple.png in Resources */,
43A4BAEB15C893E300F3B8D4 /* FriendsListViewController.xib in Resources */, 43A4BAEB15C893E300F3B8D4 /* FriendsListViewController.xib in Resources */,
432EBD0E15D1A2B00000729D /* fountain_pen_on.png in Resources */, 432EBD0E15D1A2B00000729D /* fountain_pen_on.png in Resources */,
432EBD0F15D1A2B00000729D /* fountain_pen_on@2x.png in Resources */, 432EBD0F15D1A2B00000729D /* fountain_pen_on@2x.png in Resources */,
432EBD1615D1A7800000729D /* user_on.png in Resources */, 432EBD1615D1A7800000729D /* user_on.png in Resources */,
FFB9BE4C17F4B65B00FE0A36 /* logo_76.png in Resources */,
432EBD1715D1A7800000729D /* user_on@2x.png in Resources */, 432EBD1715D1A7800000729D /* user_on@2x.png in Resources */,
43C3D40415D44EA30066D36D /* user_light.png in Resources */, 43C3D40415D44EA30066D36D /* user_light.png in Resources */,
43C3D40515D44EA30066D36D /* user_light@2x.png in Resources */, 43C3D40515D44EA30066D36D /* user_light@2x.png in Resources */,
43C3D40815D4680C0066D36D /* green_focus.png in Resources */,
43C3D40A15D468BA0066D36D /* all.png in Resources */, 43C3D40A15D468BA0066D36D /* all.png in Resources */,
43C3D40C15D469010066D36D /* unread_yellow.png in Resources */, 43C3D40C15D469010066D36D /* unread_yellow.png in Resources */,
43C3D41015D46D2B0066D36D /* green_focus@2x.png in Resources */,
43C3D41215D46D330066D36D /* all@2x.png in Resources */, 43C3D41215D46D330066D36D /* all@2x.png in Resources */,
43B232C115D5F61700D035B4 /* AuthorizeServicesViewController.xib in Resources */, 43B232C115D5F61700D035B4 /* AuthorizeServicesViewController.xib in Resources */,
430C4BC015D7208600B9F63B /* facebook.png in Resources */, 430C4BC015D7208600B9F63B /* facebook.png in Resources */,
@ -2279,7 +2225,6 @@
43BC459315D9F76000205B69 /* facebook_button_on@2x.png in Resources */, 43BC459315D9F76000205B69 /* facebook_button_on@2x.png in Resources */,
43BC459415D9F76000205B69 /* facebook_button.png in Resources */, 43BC459415D9F76000205B69 /* facebook_button.png in Resources */,
43BC459515D9F76000205B69 /* facebook_button@2x.png in Resources */, 43BC459515D9F76000205B69 /* facebook_button@2x.png in Resources */,
FF546DF71602930100948020 /* Default-568h@2x.png in Resources */,
FF546DF9160298E500948020 /* fleuron@2x.png in Resources */, FF546DF9160298E500948020 /* fleuron@2x.png in Resources */,
FFDE35D2161B9E600034BFDE /* disclosure_border.png in Resources */, FFDE35D2161B9E600034BFDE /* disclosure_border.png in Resources */,
FFDE35ED1627A1C40034BFDE /* FeedDetailMenuViewController.xib in Resources */, FFDE35ED1627A1C40034BFDE /* FeedDetailMenuViewController.xib in Resources */,
@ -2292,9 +2237,10 @@
FF4130A0162CECAE00DDB6A7 /* email.png in Resources */, FF4130A0162CECAE00DDB6A7 /* email.png in Resources */,
FF6A23391644957800E15989 /* StoryPageControl.xib in Resources */, FF6A23391644957800E15989 /* StoryPageControl.xib in Resources */,
FF67D3B7168977690057A7DA /* TrainerViewController.xib in Resources */, FF67D3B7168977690057A7DA /* TrainerViewController.xib in Resources */,
FF67D3B916897AD80057A7DA /* TrainerViewController~ipad.xib in Resources */,
FF67D3BB168A70630057A7DA /* trainer.css in Resources */, FF67D3BB168A70630057A7DA /* trainer.css in Resources */,
FFCDD8F617F4BCB4000C6483 /* Default-portrait.png in Resources */,
FF67D3C1168A708D0057A7DA /* storyDetailView.css in Resources */, FF67D3C1168A708D0057A7DA /* storyDetailView.css in Resources */,
FFCDD8F317F4BCB4000C6483 /* Default-568h@2x.png in Resources */,
FF85BF6016D5A587002D334D /* nav_icn_activity_hover.png in Resources */, FF85BF6016D5A587002D334D /* nav_icn_activity_hover.png in Resources */,
FF85BF6116D5A587002D334D /* nav_icn_settings.png in Resources */, FF85BF6116D5A587002D334D /* nav_icn_settings.png in Resources */,
FF85BF6316D5A5A8002D334D /* nav_icn_add.png in Resources */, FF85BF6316D5A5A8002D334D /* nav_icn_add.png in Resources */,
@ -2318,24 +2264,6 @@
FF4151C416DEDF9D0013E84B /* markread@2x.png in Resources */, FF4151C416DEDF9D0013E84B /* markread@2x.png in Resources */,
FF4151C716DEF1A80013E84B /* original_button.png in Resources */, FF4151C716DEF1A80013E84B /* original_button.png in Resources */,
FF4151C816DEF1A80013E84B /* original_button@2x.png in Resources */, FF4151C816DEF1A80013E84B /* original_button@2x.png in Resources */,
FF4151E916DEF9960013E84B /* back_button_background.png in Resources */,
FF4151EA16DEF9960013E84B /* back_button_background@2x.png in Resources */,
FF4151EB16DEF9960013E84B /* back_button_landscape_background.png in Resources */,
FF4151EC16DEF9960013E84B /* back_button_landscape_background@2x.png in Resources */,
FF4151ED16DEF9960013E84B /* back_button_landscape_selected_background.png in Resources */,
FF4151EE16DEF9960013E84B /* back_button_landscape_selected_background@2x.png in Resources */,
FF4151EF16DEF9960013E84B /* back_button_selected_background.png in Resources */,
FF4151F016DEF9960013E84B /* back_button_selected_background@2x.png in Resources */,
FFCF51A316E020DD008C7C42 /* toolbar_background.png in Resources */,
FFCF51A416E020DD008C7C42 /* toolbar_background@2x.png in Resources */,
FFCF51A716E028B0008C7C42 /* navbar_background.png in Resources */,
FFCF51A816E028B0008C7C42 /* navbar_background@2x.png in Resources */,
FFCF51AB16E029E6008C7C42 /* navbar_landscape_background.png in Resources */,
FFCF51AC16E029E6008C7C42 /* navbar_landscape_background@2x.png in Resources */,
FFCF51C516E0300F008C7C42 /* button_selected.png in Resources */,
FFCF51C616E0300F008C7C42 /* button_selected@2x.png in Resources */,
FFCF51C716E0300F008C7C42 /* button.png in Resources */,
FFCF51C816E0300F008C7C42 /* button@2x.png in Resources */,
FFC5F30B16E2D2C2007AC72C /* story_share_appnet_active.png in Resources */, FFC5F30B16E2D2C2007AC72C /* story_share_appnet_active.png in Resources */,
FFC5F30C16E2D2C2007AC72C /* story_share_appnet_active@2x.png in Resources */, FFC5F30C16E2D2C2007AC72C /* story_share_appnet_active@2x.png in Resources */,
FFC5F30D16E2D2C2007AC72C /* story_share_appnet.png in Resources */, FFC5F30D16E2D2C2007AC72C /* story_share_appnet.png in Resources */,
@ -2348,10 +2276,6 @@
FFC5F31416E2D2C2007AC72C /* story_share_twitter_active@2x.png in Resources */, FFC5F31416E2D2C2007AC72C /* story_share_twitter_active@2x.png in Resources */,
FFC5F31516E2D2C2007AC72C /* story_share_twitter.png in Resources */, FFC5F31516E2D2C2007AC72C /* story_share_twitter.png in Resources */,
FFC5F31616E2D2C2007AC72C /* story_share_twitter@2x.png in Resources */, FFC5F31616E2D2C2007AC72C /* story_share_twitter@2x.png in Resources */,
FFC5F31B16E2E9FB007AC72C /* toolbar_button_landscape_selected.png in Resources */,
FFC5F31C16E2E9FB007AC72C /* toolbar_button_landscape.png in Resources */,
FFC5F31D16E2E9FB007AC72C /* toolbar_button_landscape@2x.png in Resources */,
FFC5F31E16E2E9FB007AC72C /* toolbar_button_selected_landscape@2x.png in Resources */,
FFC5F32016E2F24B007AC72C /* white_spacer.png in Resources */, FFC5F32016E2F24B007AC72C /* white_spacer.png in Resources */,
FF22FE4616E410A60046165A /* folder_collapse.png in Resources */, FF22FE4616E410A60046165A /* folder_collapse.png in Resources */,
FF22FE4716E410A60046165A /* folder_expand.png in Resources */, FF22FE4716E410A60046165A /* folder_expand.png in Resources */,
@ -2367,6 +2291,7 @@
FF22FE6E16E554540046165A /* barbutton_refresh.png in Resources */, FF22FE6E16E554540046165A /* barbutton_refresh.png in Resources */,
FF22FE6F16E554540046165A /* barbutton_refresh@2x.png in Resources */, FF22FE6F16E554540046165A /* barbutton_refresh@2x.png in Resources */,
FF22FE7216E554FD0046165A /* barbutton_sendto.png in Resources */, FF22FE7216E554FD0046165A /* barbutton_sendto.png in Resources */,
FFB9BE4D17F4B65B00FE0A36 /* logo_80.png in Resources */,
FF22FE7316E554FD0046165A /* barbutton_sendto@2x.png in Resources */, FF22FE7316E554FD0046165A /* barbutton_sendto@2x.png in Resources */,
FF22FE7616E557D80046165A /* toolbar_tall_background.png in Resources */, FF22FE7616E557D80046165A /* toolbar_tall_background.png in Resources */,
FF22FE7716E557D80046165A /* toolbar_tall_background@2x.png in Resources */, FF22FE7716E557D80046165A /* toolbar_tall_background@2x.png in Resources */,
@ -2392,8 +2317,11 @@
FFDD846616E8871A000AA0A2 /* menu_icn_train.png in Resources */, FFDD846616E8871A000AA0A2 /* menu_icn_train.png in Resources */,
FFDD846716E8871A000AA0A2 /* menu_icn_train@2x.png in Resources */, FFDD846716E8871A000AA0A2 /* menu_icn_train@2x.png in Resources */,
FFDD846A16E88722000AA0A2 /* clock.png in Resources */, FFDD846A16E88722000AA0A2 /* clock.png in Resources */,
FFCDD8F417F4BCB4000C6483 /* Default-landscape.png in Resources */,
FFDD846B16E88722000AA0A2 /* clock@2x.png in Resources */, FFDD846B16E88722000AA0A2 /* clock@2x.png in Resources */,
FFCDD8F717F4BCB4000C6483 /* Default-portrait@2x.png in Resources */,
FFDD847816E887D3000AA0A2 /* g_icn_focus.png in Resources */, FFDD847816E887D3000AA0A2 /* g_icn_focus.png in Resources */,
FFB9BE4B17F4B65B00FE0A36 /* logo_58.png in Resources */,
FFDD847916E887D3000AA0A2 /* g_icn_focus@2x.png in Resources */, FFDD847916E887D3000AA0A2 /* g_icn_focus@2x.png in Resources */,
FFDD847A16E887D3000AA0A2 /* g_icn_folder_add.png in Resources */, FFDD847A16E887D3000AA0A2 /* g_icn_folder_add.png in Resources */,
FFDD847B16E887D3000AA0A2 /* g_icn_folder_add@2x.png in Resources */, FFDD847B16E887D3000AA0A2 /* g_icn_folder_add@2x.png in Resources */,
@ -2409,6 +2337,7 @@
FFDD848716E8EB1E000AA0A2 /* share@2x.png in Resources */, FFDD848716E8EB1E000AA0A2 /* share@2x.png in Resources */,
FFDD848A16E8EBF8000AA0A2 /* train.png in Resources */, FFDD848A16E8EBF8000AA0A2 /* train.png in Resources */,
FFDD848B16E8EBF8000AA0A2 /* train@2x.png in Resources */, FFDD848B16E8EBF8000AA0A2 /* train@2x.png in Resources */,
FFB9BE4A17F4B65B00FE0A36 /* logo_40.png in Resources */,
FFDD848E16E8ED75000AA0A2 /* menu_icn_share.png in Resources */, FFDD848E16E8ED75000AA0A2 /* menu_icn_share.png in Resources */,
FFDD848F16E8ED75000AA0A2 /* menu_icn_share@2x.png in Resources */, FFDD848F16E8ED75000AA0A2 /* menu_icn_share@2x.png in Resources */,
FFB5F50B17187B6F00C8B432 /* big_world.png in Resources */, FFB5F50B17187B6F00C8B432 /* big_world.png in Resources */,
@ -2416,6 +2345,7 @@
FFB757FF1727098D001D132F /* menu_icn_mail@2x.png in Resources */, FFB757FF1727098D001D132F /* menu_icn_mail@2x.png in Resources */,
FFECD019172B105800D45A62 /* UIActivitySafari.png in Resources */, FFECD019172B105800D45A62 /* UIActivitySafari.png in Resources */,
FFECD01A172B105800D45A62 /* UIActivitySafari@2x.png in Resources */, FFECD01A172B105800D45A62 /* UIActivitySafari@2x.png in Resources */,
FFB9BE4917F4B65B00FE0A36 /* logo_29.png in Resources */,
FF8364BB1755759A008F5C58 /* traverse_text.png in Resources */, FF8364BB1755759A008F5C58 /* traverse_text.png in Resources */,
FF8364BC1755759A008F5C58 /* traverse_text@2x.png in Resources */, FF8364BC1755759A008F5C58 /* traverse_text@2x.png in Resources */,
FF8364BF1756949E008F5C58 /* traverse_text_on.png in Resources */, FF8364BF1756949E008F5C58 /* traverse_text_on.png in Resources */,
@ -2434,6 +2364,7 @@
FFAF538F1799D1C800C7FCCB /* TUSafariActivity.strings in Resources */, FFAF538F1799D1C800C7FCCB /* TUSafariActivity.strings in Resources */,
FFAF53901799D1C800C7FCCB /* Safari.png in Resources */, FFAF53901799D1C800C7FCCB /* Safari.png in Resources */,
FFAF53911799D1C800C7FCCB /* Safari@2x.png in Resources */, FFAF53911799D1C800C7FCCB /* Safari@2x.png in Resources */,
FFCDD8F517F4BCB4000C6483 /* Default-landscape@2x.png in Resources */,
FFAF53921799D1C800C7FCCB /* Safari@2x~ipad.png in Resources */, FFAF53921799D1C800C7FCCB /* Safari@2x~ipad.png in Resources */,
FFAF53931799D1C800C7FCCB /* Safari~ipad.png in Resources */, FFAF53931799D1C800C7FCCB /* Safari~ipad.png in Resources */,
FFAF53AD1799E69D00C7FCCB /* PocketActivity@2x~ipad.png in Resources */, FFAF53AD1799E69D00C7FCCB /* PocketActivity@2x~ipad.png in Resources */,
@ -2442,6 +2373,7 @@
FFAF53B01799E69D00C7FCCB /* PocketActivity~iphone.png in Resources */, FFAF53B01799E69D00C7FCCB /* PocketActivity~iphone.png in Resources */,
FFAF53B61799E69D00C7FCCB /* Readability-activity-iPad.png in Resources */, FFAF53B61799E69D00C7FCCB /* Readability-activity-iPad.png in Resources */,
FFAF53B71799E69D00C7FCCB /* Readability-activity-iPad@2x.png in Resources */, FFAF53B71799E69D00C7FCCB /* Readability-activity-iPad@2x.png in Resources */,
FFCDD8F817F4BCB4000C6483 /* Default.png in Resources */,
FFAF53B81799E69D00C7FCCB /* Readability-activity-iPhone.png in Resources */, FFAF53B81799E69D00C7FCCB /* Readability-activity-iPhone.png in Resources */,
FFAF53B91799E69D00C7FCCB /* Readability-activity-iPhone@2x.png in Resources */, FFAF53B91799E69D00C7FCCB /* Readability-activity-iPhone@2x.png in Resources */,
FF5D40051799F53C00349659 /* LICENSE in Resources */, FF5D40051799F53C00349659 /* LICENSE in Resources */,
@ -2452,6 +2384,7 @@
FF5D40131799F70200349659 /* ARChromeActivity@2x~ipad.png in Resources */, FF5D40131799F70200349659 /* ARChromeActivity@2x~ipad.png in Resources */,
FF5D40141799F70200349659 /* ARChromeActivity~ipad.png in Resources */, FF5D40141799F70200349659 /* ARChromeActivity~ipad.png in Resources */,
FF5D4017179A00B900349659 /* traverse_send.png in Resources */, FF5D4017179A00B900349659 /* traverse_send.png in Resources */,
FFCDD8FA17F50C08000C6483 /* drag_icon.png in Resources */,
FF5D4018179A00B900349659 /* traverse_send@2x.png in Resources */, FF5D4018179A00B900349659 /* traverse_send@2x.png in Resources */,
FF5D401B179A03E700349659 /* traverse_previous_off.png in Resources */, FF5D401B179A03E700349659 /* traverse_previous_off.png in Resources */,
FF5D401C179A03E700349659 /* traverse_previous_off@2x.png in Resources */, FF5D401C179A03E700349659 /* traverse_previous_off@2x.png in Resources */,
@ -2486,6 +2419,7 @@
78095E35128EF30D00230C8E /* ASIDownloadCache.m in Sources */, 78095E35128EF30D00230C8E /* ASIDownloadCache.m in Sources */,
78095E36128EF30D00230C8E /* ASIFormDataRequest.m in Sources */, 78095E36128EF30D00230C8E /* ASIFormDataRequest.m in Sources */,
78095E37128EF30D00230C8E /* ASIHTTPRequest.m in Sources */, 78095E37128EF30D00230C8E /* ASIHTTPRequest.m in Sources */,
FFCDD8FE17F6368F000C6483 /* MCSwipeTableViewCell.m in Sources */,
78095E38128EF30D00230C8E /* ASIInputStream.m in Sources */, 78095E38128EF30D00230C8E /* ASIInputStream.m in Sources */,
78095E39128EF30D00230C8E /* ASINetworkQueue.m in Sources */, 78095E39128EF30D00230C8E /* ASINetworkQueue.m in Sources */,
78095EC9128F30B500230C8E /* OriginalStoryViewController.m in Sources */, 78095EC9128F30B500230C8E /* OriginalStoryViewController.m in Sources */,
@ -2495,6 +2429,7 @@
FFD887F01445F1E800385399 /* AddSiteAutocompleteCell.m in Sources */, FFD887F01445F1E800385399 /* AddSiteAutocompleteCell.m in Sources */,
FFE5322F144C8AC300ACFDE0 /* Utilities.m in Sources */, FFE5322F144C8AC300ACFDE0 /* Utilities.m in Sources */,
FFD1D7311459B63500E46F89 /* BaseViewController.m in Sources */, FFD1D7311459B63500E46F89 /* BaseViewController.m in Sources */,
FF9B8BB217F2351A0036A41C /* NBBarButtonItem.m in Sources */,
FF2D8CAF1488633A00057B80 /* Reachability.m in Sources */, FF2D8CAF1488633A00057B80 /* Reachability.m in Sources */,
FF2D8CE514893BC000057B80 /* MoveSiteViewController.m in Sources */, FF2D8CE514893BC000057B80 /* MoveSiteViewController.m in Sources */,
433323CD158968ED0025064D /* FirstTimeUserViewController.m in Sources */, 433323CD158968ED0025064D /* FirstTimeUserViewController.m in Sources */,
@ -2601,6 +2536,7 @@
FF5D3FFF1799F53C00349659 /* VUPinboardActivity.m in Sources */, FF5D3FFF1799F53C00349659 /* VUPinboardActivity.m in Sources */,
FF5D40001799F53C00349659 /* VUPinboardViewController.m in Sources */, FF5D40001799F53C00349659 /* VUPinboardViewController.m in Sources */,
FF5D40011799F53C00349659 /* BBNetworkRequest.m in Sources */, FF5D40011799F53C00349659 /* BBNetworkRequest.m in Sources */,
FFCDD90117F65A71000C6483 /* NBSwipeableCell.m in Sources */,
FF5D40021799F53C00349659 /* SSKeychain.m in Sources */, FF5D40021799F53C00349659 /* SSKeychain.m in Sources */,
FF5D40031799F53C00349659 /* VUDialogViewController.m in Sources */, FF5D40031799F53C00349659 /* VUDialogViewController.m in Sources */,
FF5D40041799F53C00349659 /* VUGradientButton.m in Sources */, FF5D40041799F53C00349659 /* VUGradientButton.m in Sources */,
@ -2645,20 +2581,19 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = YES; ALWAYS_SEARCH_USER_PATHS = YES;
ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)";
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
CODE_SIGN_ENTITLEMENTS = Entitlements.entitlements;
CODE_SIGN_IDENTITY = "iPhone Distribution: NewsBlur, Inc. (HR7P97SD72)"; CODE_SIGN_IDENTITY = "iPhone Distribution: NewsBlur, Inc. (HR7P97SD72)";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: NewsBlur, Inc. (HR7P97SD72)";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO; GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0; GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = NewsBlur_Prefix.pch; GCC_PREFIX_HEADER = NewsBlur_Prefix.pch;
GCC_THUMB_SUPPORT = NO; GCC_THUMB_SUPPORT = NO;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_VERSION = "";
HEADER_SEARCH_PATHS = ""; HEADER_SEARCH_PATHS = "";
INFOPLIST_FILE = "NewsBlur-iPhone-Info.plist"; INFOPLIST_FILE = "NewsBlur-iPhone-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 6.0; IPHONEOS_DEPLOYMENT_TARGET = 7.0;
LIBRARY_SEARCH_PATHS = ( LIBRARY_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"\"$(SRCROOT)\"", "\"$(SRCROOT)\"",
@ -2671,10 +2606,8 @@
"-all_load", "-all_load",
); );
PRODUCT_NAME = NewsBlur; PRODUCT_NAME = NewsBlur;
PROVISIONING_PROFILE = "BF7FE540-5E58-4C3F-88D5-AD73981C42C0"; PROVISIONING_PROFILE = "954389F4-8E6B-4312-9C44-7DCD5EAD40A5";
"PROVISIONING_PROFILE[sdk=iphoneos*]" = "BF7FE540-5E58-4C3F-88D5-AD73981C42C0";
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
VALID_ARCHS = armv7;
"WARNING_CFLAGS[arch=*]" = "-Wall"; "WARNING_CFLAGS[arch=*]" = "-Wall";
}; };
name = Debug; name = Debug;
@ -2683,18 +2616,17 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)";
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
CODE_SIGN_ENTITLEMENTS = Entitlements.entitlements;
CODE_SIGN_IDENTITY = "iPhone Distribution: NewsBlur, Inc. (HR7P97SD72)"; CODE_SIGN_IDENTITY = "iPhone Distribution: NewsBlur, Inc. (HR7P97SD72)";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: NewsBlur, Inc. (HR7P97SD72)";
COPY_PHASE_STRIP = YES; COPY_PHASE_STRIP = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = NewsBlur_Prefix.pch; GCC_PREFIX_HEADER = NewsBlur_Prefix.pch;
GCC_THUMB_SUPPORT = NO; GCC_THUMB_SUPPORT = NO;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_VERSION = "";
HEADER_SEARCH_PATHS = ""; HEADER_SEARCH_PATHS = "";
INFOPLIST_FILE = "NewsBlur-iPhone-Info.plist"; INFOPLIST_FILE = "NewsBlur-iPhone-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 6.0; IPHONEOS_DEPLOYMENT_TARGET = 7.0;
LIBRARY_SEARCH_PATHS = ( LIBRARY_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"\"$(SRCROOT)\"", "\"$(SRCROOT)\"",
@ -2706,19 +2638,17 @@
"-all_load", "-all_load",
); );
PRODUCT_NAME = NewsBlur; PRODUCT_NAME = NewsBlur;
PROVISIONING_PROFILE = "BF7FE540-5E58-4C3F-88D5-AD73981C42C0"; PROVISIONING_PROFILE = "954389F4-8E6B-4312-9C44-7DCD5EAD40A5";
"PROVISIONING_PROFILE[sdk=iphoneos*]" = "BF7FE540-5E58-4C3F-88D5-AD73981C42C0";
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
VALID_ARCHS = armv7;
}; };
name = Release; name = Release;
}; };
C01FCF4F08A954540054247B /* Debug */ = { C01FCF4F08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_IDENTITY = "iPhone Developer: Samuel Clay (3PN8E5365D)";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Samuel Clay (3PN8E5365D)";
COPY_PHASE_STRIP = YES; COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_C_LANGUAGE_STANDARD = "compiler-default"; GCC_C_LANGUAGE_STANDARD = "compiler-default";
@ -2728,20 +2658,20 @@
IPHONEOS_DEPLOYMENT_TARGET = 6.0; IPHONEOS_DEPLOYMENT_TARGET = 6.0;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = "-ObjC"; OTHER_LDFLAGS = "-ObjC";
PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE = "EB97D956-BB90-4F2F-9919-F71949B04B3F";
"PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; "PROVISIONING_PROFILE[sdk=iphoneos*]" = "EB97D956-BB90-4F2F-9919-F71949B04B3F";
RUN_CLANG_STATIC_ANALYZER = YES; RUN_CLANG_STATIC_ANALYZER = YES;
SDKROOT = iphoneos; SDKROOT = iphoneos7.0;
STRIP_INSTALLED_PRODUCT = YES; STRIP_INSTALLED_PRODUCT = YES;
VALID_ARCHS = "arm64 armv7 armv7s"; VALID_ARCHS = "armv7s armv7 arm64";
}; };
name = Debug; name = Debug;
}; };
C01FCF5008A954540054247B /* Release */ = { C01FCF5008A954540054247B /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_IDENTITY = "iPhone Developer: Samuel Clay (3PN8E5365D)";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Samuel Clay (3PN8E5365D)";
COPY_PHASE_STRIP = YES; COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_C_LANGUAGE_STANDARD = "compiler-default"; GCC_C_LANGUAGE_STANDARD = "compiler-default";
@ -2749,13 +2679,14 @@
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)/**"; HEADER_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)/**";
IPHONEOS_DEPLOYMENT_TARGET = 6.0; IPHONEOS_DEPLOYMENT_TARGET = 6.0;
ONLY_ACTIVE_ARCH = NO;
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
OTHER_LDFLAGS = "-ObjC"; OTHER_LDFLAGS = "-ObjC";
PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE = "EB97D956-BB90-4F2F-9919-F71949B04B3F";
"PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; "PROVISIONING_PROFILE[sdk=iphoneos*]" = "EB97D956-BB90-4F2F-9919-F71949B04B3F";
SDKROOT = iphoneos; SDKROOT = iphoneos7.0;
STRIP_INSTALLED_PRODUCT = YES; STRIP_INSTALLED_PRODUCT = YES;
VALID_ARCHS = "arm64 armv7 armv7s"; VALID_ARCHS = "armv7s armv7 arm64";
}; };
name = Release; name = Release;
}; };

View file

@ -2,6 +2,8 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import "Underscore.h" #import "Underscore.h"
#import <SystemConfiguration/SystemConfiguration.h>
#import <MobileCoreServices/MobileCoreServices.h>
//#define DEBUG 1 //#define DEBUG 1

View file

@ -59,22 +59,7 @@
@end @end
@interface IASKAppSettingsViewController : UITableViewController <IASKViewController, UITextFieldDelegate, MFMailComposeViewControllerDelegate> { @interface IASKAppSettingsViewController : UITableViewController <IASKViewController, UITextFieldDelegate, MFMailComposeViewControllerDelegate>
id<IASKSettingsDelegate> _delegate;
NSMutableArray *_viewList;
IASKSettingsReader *_settingsReader;
id<IASKSettingsStore> _settingsStore;
NSString *_file;
id _currentFirstResponder;
BOOL _showCreditsFooter;
BOOL _showDoneButton;
NSSet *_hiddenKeys;
}
@property (nonatomic, assign) IBOutlet id delegate; @property (nonatomic, assign) IBOutlet id delegate;
@property (nonatomic, copy) NSString *file; @property (nonatomic, copy) NSString *file;

View file

@ -27,9 +27,13 @@
#import "IASKSpecifierValuesViewController.h" #import "IASKSpecifierValuesViewController.h"
#import "IASKTextField.h" #import "IASKTextField.h"
static const CGFloat KEYBOARD_ANIMATION_DURATION = 0.3; #if !__has_feature(objc_arc)
static const CGFloat MINIMUM_SCROLL_FRACTION = 0.2; #error "IASK needs ARC"
static const CGFloat MAXIMUM_SCROLL_FRACTION = 0.8; #endif
static const CGFloat KEYBOARD_ANIMATION_DURATION = 0.3f;
static const CGFloat MINIMUM_SCROLL_FRACTION = 0.2f;
static const CGFloat MAXIMUM_SCROLL_FRACTION = 0.8f;
static NSString *kIASKCredits = @"Powered by InAppSettingsKit"; // Leave this as-is!!! static NSString *kIASKCredits = @"Powered by InAppSettingsKit"; // Leave this as-is!!!
@ -40,9 +44,15 @@ static NSString *kIASKCredits = @"Powered by InAppSettingsKit"; // Leave this as
CGRect IASKCGRectSwap(CGRect rect); CGRect IASKCGRectSwap(CGRect rect);
@interface IASKAppSettingsViewController () @interface IASKAppSettingsViewController () {
@property (nonatomic, retain) NSMutableArray *viewList; IASKSettingsReader *_settingsReader;
@property (nonatomic, retain) id currentFirstResponder; id<IASKSettingsStore> _settingsStore;
id _currentFirstResponder;
__weak UIViewController *_currentChildViewController;
}
@property (nonatomic, strong) id currentFirstResponder;
- (void)_textChanged:(id)sender; - (void)_textChanged:(id)sender;
- (void)synchronizeSettings; - (void)synchronizeSettings;
@ -51,16 +61,10 @@ CGRect IASKCGRectSwap(CGRect rect);
@end @end
@implementation IASKAppSettingsViewController @implementation IASKAppSettingsViewController
//synthesize properties from protocol
@synthesize delegate = _delegate;
@synthesize viewList = _viewList;
@synthesize settingsReader = _settingsReader; @synthesize settingsReader = _settingsReader;
@synthesize file = _file;
@synthesize currentFirstResponder = _currentFirstResponder;
@synthesize showCreditsFooter = _showCreditsFooter;
@synthesize showDoneButton = _showDoneButton;
@synthesize settingsStore = _settingsStore; @synthesize settingsStore = _settingsStore;
@synthesize hiddenKeys = _hiddenKeys; @synthesize file = _file;
#pragma mark accessors #pragma mark accessors
- (IASKSettingsReader*)settingsReader { - (IASKSettingsReader*)settingsReader {
@ -81,20 +85,15 @@ CGRect IASKCGRectSwap(CGRect rect);
if (!_file) { if (!_file) {
return @"Root"; return @"Root";
} }
return [[_file retain] autorelease]; return _file;
} }
- (void)setFile:(NSString *)file { - (void)setFile:(NSString *)file {
if (file != _file) { _file = [file copy];
[_file release];
_file = [file copy];
}
self.tableView.contentOffset = CGPointMake(0, 0); self.tableView.contentOffset = CGPointMake(0, 0);
self.settingsReader = nil; // automatically initializes itself self.settingsReader = nil; // automatically initializes itself
[_hiddenKeys release], _hiddenKeys = nil; _hiddenKeys = nil;
[self.tableView reloadData]; [self.tableView reloadData];
} }
- (BOOL)isPad { - (BOOL)isPad {
@ -117,8 +116,6 @@ CGRect IASKCGRectSwap(CGRect rect);
} }
self = [super initWithStyle:UITableViewStyleGrouped]; self = [super initWithStyle:UITableViewStyleGrouped];
if (self) { if (self) {
self.tableView.delegate = self;
self.tableView.dataSource = self;
_showDoneButton = YES; _showDoneButton = YES;
// If set to YES, will display credits for InAppSettingsKit creators // If set to YES, will display credits for InAppSettingsKit creators
_showCreditsFooter = YES; _showCreditsFooter = YES;
@ -135,24 +132,17 @@ CGRect IASKCGRectSwap(CGRect rect);
return [self initWithStyle:UITableViewStyleGrouped]; return [self initWithStyle:UITableViewStyleGrouped];
} }
- (NSMutableArray *)viewList {
if (!_viewList) {
_viewList = [[NSMutableArray alloc] init];
[_viewList addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"IASKSpecifierValuesView", @"ViewName",nil]];
[_viewList addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"IASKAppSettingsView", @"ViewName",nil]];
}
return _viewList;
}
- (void) viewDidLoad { - (void) viewDidLoad {
[super viewDidLoad]; [super viewDidLoad];
if ([self isPad]) { if ([self isPad]) {
self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLineEtched; #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
} if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) // don't use etched style on iOS 7
#endif
self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLineEtched;
}
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapToEndEdit:)]; UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapToEndEdit:)];
tapGesture.cancelsTouchesInView = NO; tapGesture.cancelsTouchesInView = NO;
[self.tableView addGestureRecognizer:tapGesture]; [self.tableView addGestureRecognizer:tapGesture];
[tapGesture release];
} }
- (void)viewDidUnload { - (void)viewDidUnload {
@ -161,7 +151,6 @@ CGRect IASKCGRectSwap(CGRect rect);
// Release any retained subviews of the main view. // Release any retained subviews of the main view.
// e.g. self.myOutlet = nil; // e.g. self.myOutlet = nil;
self.view = nil; self.view = nil;
self.viewList = nil;
} }
- (void)viewWillAppear:(BOOL)animated { - (void)viewWillAppear:(BOOL)animated {
@ -175,13 +164,11 @@ CGRect IASKCGRectSwap(CGRect rect);
[self.tableView selectRowAtIndexPath:selectedIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone]; [self.tableView selectRowAtIndexPath:selectedIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
} }
self.navigationItem.rightBarButtonItem = nil;
if (_showDoneButton) { if (_showDoneButton) {
UIBarButtonItem *buttonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone UIBarButtonItem *buttonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self target:self
action:@selector(dismiss:)]; action:@selector(dismiss:)];
self.navigationItem.rightBarButtonItem = buttonItem; self.navigationItem.rightBarButtonItem = buttonItem;
[buttonItem release];
} }
if (!self.title) { if (!self.title) {
self.title = NSLocalizedString(@"Settings", @""); self.title = NSLocalizedString(@"Settings", @"");
@ -228,13 +215,6 @@ CGRect IASKCGRectSwap(CGRect rect);
return YES; return YES;
} }
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)setHiddenKeys:(NSSet *)theHiddenKeys { - (void)setHiddenKeys:(NSSet *)theHiddenKeys {
[self setHiddenKeys:theHiddenKeys animated:NO]; [self setHiddenKeys:theHiddenKeys animated:NO];
} }
@ -243,7 +223,7 @@ CGRect IASKCGRectSwap(CGRect rect);
- (void)setHiddenKeys:(NSSet*)theHiddenKeys animated:(BOOL)animated { - (void)setHiddenKeys:(NSSet*)theHiddenKeys animated:(BOOL)animated {
if (_hiddenKeys != theHiddenKeys) { if (_hiddenKeys != theHiddenKeys) {
NSSet *oldHiddenKeys = _hiddenKeys; NSSet *oldHiddenKeys = _hiddenKeys;
_hiddenKeys = [theHiddenKeys retain]; _hiddenKeys = theHiddenKeys;
if (animated) { if (animated) {
[self.tableView beginUpdates]; [self.tableView beginUpdates];
@ -266,7 +246,7 @@ CGRect IASKCGRectSwap(CGRect rect);
// calculate sections to be deleted // calculate sections to be deleted
NSMutableIndexSet *hideSections = [NSMutableIndexSet indexSet]; NSMutableIndexSet *hideSections = [NSMutableIndexSet indexSet];
for (NSInteger section = 0; section < [self numberOfSectionsInTableView:self.tableView ]; section++) { for (NSInteger section = 0; section < [self numberOfSectionsInTableView:self.tableView ]; section++) {
NSUInteger rowsInSection = 0; NSInteger rowsInSection = 0;
for (NSIndexPath *indexPath in hideIndexPaths) { for (NSIndexPath *indexPath in hideIndexPaths) {
if (indexPath.section == section) { if (indexPath.section == section) {
rowsInSection++; rowsInSection++;
@ -293,7 +273,7 @@ CGRect IASKCGRectSwap(CGRect rect);
// calculate sections to be inserted // calculate sections to be inserted
NSMutableIndexSet *showSections = [NSMutableIndexSet indexSet]; NSMutableIndexSet *showSections = [NSMutableIndexSet indexSet];
for (NSInteger section = 0; section < [self.settingsReader numberOfSections]; section++) { for (NSInteger section = 0; section < [self.settingsReader numberOfSections]; section++) {
NSUInteger rowsInSection = 0; NSInteger rowsInSection = 0;
for (NSIndexPath *indexPath in showIndexPaths) { for (NSIndexPath *indexPath in showIndexPaths) {
if (indexPath.section == section) { if (indexPath.section == section) {
rowsInSection++; rowsInSection++;
@ -304,7 +284,7 @@ CGRect IASKCGRectSwap(CGRect rect);
} }
} }
UITableViewRowAnimation animation = animated ? UITableViewRowAnimationTop : UITableViewRowAnimationNone; UITableViewRowAnimation animation = animated ? UITableViewRowAnimationAutomatic : UITableViewRowAnimationNone;
[self.tableView deleteSections:hideSections withRowAnimation:animation]; [self.tableView deleteSections:hideSections withRowAnimation:animation];
[self.tableView deleteRowsAtIndexPaths:hideIndexPaths withRowAnimation:animation]; [self.tableView deleteRowsAtIndexPaths:hideIndexPaths withRowAnimation:animation];
[self.tableView insertSections:showSections withRowAnimation:animation]; [self.tableView insertSections:showSections withRowAnimation:animation];
@ -314,28 +294,16 @@ CGRect IASKCGRectSwap(CGRect rect);
self.settingsReader.hiddenKeys = theHiddenKeys; self.settingsReader.hiddenKeys = theHiddenKeys;
[self.tableView reloadData]; [self.tableView reloadData];
} }
[oldHiddenKeys release];
} }
IASKAppSettingsViewController *childViewController = [[self.viewList objectAtIndex:kIASKSpecifierChildViewControllerIndex] objectForKey:@"viewController"]; UIViewController *childViewController = _currentChildViewController;
if(childViewController) { if([childViewController respondsToSelector:@selector(setHiddenKeys:animated:)]) {
[childViewController setHiddenKeys:theHiddenKeys animated:animated]; [(id)childViewController setHiddenKeys:theHiddenKeys animated:animated];
} }
} }
- (void)dealloc { - (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self]; [[NSNotificationCenter defaultCenter] removeObserver:self];
[_viewList release], _viewList = nil;
[_file release], _file = nil;
[_currentFirstResponder release], _currentFirstResponder = nil;
[_settingsReader release], _settingsReader = nil;
[_settingsStore release], _settingsStore = nil;
[_hiddenKeys release], _hiddenKeys = nil;
_delegate = nil;
[super dealloc];
} }
@ -351,7 +319,7 @@ CGRect IASKCGRectSwap(CGRect rect);
} }
- (void)toggledValue:(id)sender { - (void)toggledValue:(id)sender {
IASKSwitch *toggle = [[(IASKSwitch*)sender retain] autorelease]; IASKSwitch *toggle = (IASKSwitch*)sender;
IASKSpecifier *spec = [_settingsReader specifierForKey:[toggle key]]; IASKSpecifier *spec = [_settingsReader specifierForKey:[toggle key]];
if ([toggle isOn]) { if ([toggle isOn]) {
@ -377,7 +345,7 @@ CGRect IASKCGRectSwap(CGRect rect);
} }
- (void)sliderChangedValue:(id)sender { - (void)sliderChangedValue:(id)sender {
IASKSlider *slider = [[(IASKSlider*)sender retain] autorelease]; IASKSlider *slider = (IASKSlider*)sender;
[self.settingsStore setFloat:[slider value] forKey:[slider key]]; [self.settingsStore setFloat:[slider value] forKey:[slider key]];
[[NSNotificationCenter defaultCenter] postNotificationName:kIASKAppSettingChanged [[NSNotificationCenter defaultCenter] postNotificationName:kIASKAppSettingChanged
object:[slider key] object:[slider key]
@ -435,10 +403,15 @@ CGRect IASKCGRectSwap(CGRect rect);
} }
NSString *title; NSString *title;
if ((title = [self tableView:tableView titleForHeaderInSection:section])) { if ((title = [self tableView:tableView titleForHeaderInSection:section])) {
CGSize size = [title sizeWithFont:[UIFont boldSystemFontOfSize:[UIFont labelFontSize]] NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle defaultParagraphStyle] mutableCopy];
constrainedToSize:CGSizeMake(tableView.frame.size.width - 2*kIASKHorizontalPaddingGroupTitles, INFINITY) paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
lineBreakMode:NSLineBreakByWordWrapping]; CGSize size = [title
return size.height+kIASKVerticalPaddingGroupTitles; boundingRectWithSize:CGSizeMake(tableView.frame.size.width - 2*kIASKHorizontalPaddingGroupTitles, INFINITY)
options:nil
attributes:@{NSFontAttributeName: [UIFont boldSystemFontOfSize:[UIFont labelFontSize]],
NSParagraphStyleAttributeName: paragraphStyle}
context:nil].size;
return roundf(size.height+kIASKVerticalPaddingGroupTitles);
} }
return 0; return 0;
} }
@ -467,7 +440,7 @@ CGRect IASKCGRectSwap(CGRect rect);
UITableViewCell *cell = nil; UITableViewCell *cell = nil;
if ([identifier isEqualToString:kIASKPSToggleSwitchSpecifier]) { if ([identifier isEqualToString:kIASKPSToggleSwitchSpecifier]) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kIASKPSToggleSwitchSpecifier]; cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kIASKPSToggleSwitchSpecifier];
cell.accessoryView = [[[IASKSwitch alloc] initWithFrame:CGRectMake(0, 0, 79, 27)] autorelease]; cell.accessoryView = [[IASKSwitch alloc] initWithFrame:CGRectMake(0, 0, 79, 27)];
[((IASKSwitch*)cell.accessoryView) addTarget:self action:@selector(toggledValue:) forControlEvents:UIControlEventValueChanged]; [((IASKSwitch*)cell.accessoryView) addTarget:self action:@selector(toggledValue:) forControlEvents:UIControlEventValueChanged];
cell.selectionStyle = UITableViewCellSelectionStyleNone; cell.selectionStyle = UITableViewCellSelectionStyleNone;
} }
@ -490,8 +463,8 @@ CGRect IASKCGRectSwap(CGRect rect);
} else { } else {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]; cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
} }
cell.textLabel.minimumScaleFactor = kIASKMinimumFontSize/[UIFont labelFontSize]; cell.textLabel.minimumScaleFactor = kIASKMinimumFontSize/[UIFont labelFontSize];
cell.detailTextLabel.minimumScaleFactor = kIASKMinimumFontSize/[UIFont labelFontSize]; cell.detailTextLabel.minimumScaleFactor = kIASKMinimumFontSize/[UIFont labelFontSize];
return cell; return cell;
} }
@ -505,7 +478,7 @@ CGRect IASKCGRectSwap(CGRect rect);
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:specifier.type]; UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:specifier.type];
if(nil == cell) { if(nil == cell) {
cell = [[self newCellForIdentifier:specifier.type] autorelease]; cell = [self newCellForIdentifier:specifier.type];
} }
if ([specifier.type isEqualToString:kIASKPSToggleSwitchSpecifier]) { if ([specifier.type isEqualToString:kIASKPSToggleSwitchSpecifier]) {
@ -614,7 +587,7 @@ CGRect IASKCGRectSwap(CGRect rect);
//create a set of specifier types that can't be selected //create a set of specifier types that can't be selected
static NSSet* noSelectionTypes = nil; static NSSet* noSelectionTypes = nil;
if(nil == noSelectionTypes) { if(nil == noSelectionTypes) {
noSelectionTypes = [[NSSet setWithObjects:kIASKPSToggleSwitchSpecifier, kIASKPSSliderSpecifier, nil] retain]; noSelectionTypes = [NSSet setWithObjects:kIASKPSToggleSwitchSpecifier, kIASKPSSliderSpecifier, nil];
} }
IASKSpecifier *specifier = [self.settingsReader specifierForIndexPath:indexPath]; IASKSpecifier *specifier = [self.settingsReader specifierForIndexPath:indexPath];
@ -631,115 +604,89 @@ CGRect IASKCGRectSwap(CGRect rect);
//switches and sliders can't be selected (should be captured by tableView:willSelectRowAtIndexPath: delegate method) //switches and sliders can't be selected (should be captured by tableView:willSelectRowAtIndexPath: delegate method)
assert(![[specifier type] isEqualToString:kIASKPSToggleSwitchSpecifier]); assert(![[specifier type] isEqualToString:kIASKPSToggleSwitchSpecifier]);
assert(![[specifier type] isEqualToString:kIASKPSSliderSpecifier]); assert(![[specifier type] isEqualToString:kIASKPSSliderSpecifier]);
if ([[specifier type] isEqualToString:kIASKPSMultiValueSpecifier]) { if ([[specifier type] isEqualToString:kIASKPSMultiValueSpecifier]) {
IASKSpecifierValuesViewController *targetViewController = [[self.viewList objectAtIndex:kIASKSpecifierValuesViewControllerIndex] objectForKey:@"viewController"]; IASKSpecifierValuesViewController *targetViewController = [[IASKSpecifierValuesViewController alloc] init];
if (targetViewController == nil) {
// the view controller has not been created yet, create it and set it to our viewList array
// create a new dictionary with the new view controller
NSMutableDictionary *newItemDict = [NSMutableDictionary dictionaryWithCapacity:3];
[newItemDict addEntriesFromDictionary: [self.viewList objectAtIndex:kIASKSpecifierValuesViewControllerIndex]]; // copy the title and explain strings
targetViewController = [[IASKSpecifierValuesViewController alloc] init];
// add the new view controller to the dictionary and then to the 'viewList' array
[newItemDict setObject:targetViewController forKey:@"viewController"];
[self.viewList replaceObjectAtIndex:kIASKSpecifierValuesViewControllerIndex withObject:newItemDict];
[targetViewController release];
// load the view controll back in to push it
targetViewController = [[self.viewList objectAtIndex:kIASKSpecifierValuesViewControllerIndex] objectForKey:@"viewController"];
}
[targetViewController setCurrentSpecifier:specifier]; [targetViewController setCurrentSpecifier:specifier];
targetViewController.settingsReader = self.settingsReader; targetViewController.settingsReader = self.settingsReader;
targetViewController.settingsStore = self.settingsStore; targetViewController.settingsStore = self.settingsStore;
_currentChildViewController = targetViewController;
[[self navigationController] pushViewController:targetViewController animated:YES]; [[self navigationController] pushViewController:targetViewController animated:YES];
}
else if ([[specifier type] isEqualToString:kIASKPSTextFieldSpecifier]) {
IASKPSTextFieldSpecifierViewCell *textFieldCell = (id)[tableView cellForRowAtIndexPath:indexPath];
[textFieldCell.textField becomeFirstResponder];
}
else if ([[specifier type] isEqualToString:kIASKPSChildPaneSpecifier]) {
} else if ([[specifier type] isEqualToString:kIASKPSTextFieldSpecifier]) {
IASKPSTextFieldSpecifierViewCell *textFieldCell = (id)[tableView cellForRowAtIndexPath:indexPath];
[textFieldCell.textField becomeFirstResponder];
} else if ([[specifier type] isEqualToString:kIASKPSChildPaneSpecifier]) {
Class vcClass = [specifier viewControllerClass]; Class vcClass = [specifier viewControllerClass];
if (vcClass) { if (vcClass) {
SEL initSelector = [specifier viewControllerSelector]; SEL initSelector = [specifier viewControllerSelector];
if (!initSelector) { if (!initSelector) {
initSelector = @selector(init); initSelector = @selector(init);
} }
UIViewController * vc = [vcClass performSelector:@selector(alloc)]; UIViewController * vc = [vcClass alloc];
[vc performSelector:initSelector withObject:[specifier file] withObject:[specifier key]]; #pragma clang diagnostic push
if ([vc respondsToSelector:@selector(setDelegate:)]) { #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[vc performSelector:@selector(setDelegate:) withObject:self.delegate]; vc = [vc performSelector:initSelector withObject:[specifier file] withObject:[specifier key]];
} #pragma clang diagnostic pop
if ([vc respondsToSelector:@selector(setSettingsStore:)]) { if ([vc respondsToSelector:@selector(setDelegate:)]) {
[vc performSelector:@selector(setSettingsStore:) withObject:self.settingsStore]; [vc performSelector:@selector(setDelegate:) withObject:self.delegate];
} }
if ([vc respondsToSelector:@selector(setSettingsStore:)]) {
[vc performSelector:@selector(setSettingsStore:) withObject:self.settingsStore];
}
[self.navigationController pushViewController:vc animated:YES]; [self.navigationController pushViewController:vc animated:YES];
[vc performSelector:@selector(release)];
return; return;
} }
if (nil == [specifier file]) { if (nil == [specifier file]) {
[tableView deselectRowAtIndexPath:indexPath animated:YES]; [tableView deselectRowAtIndexPath:indexPath animated:YES];
return; return;
}
IASKAppSettingsViewController *targetViewController = [[self.viewList objectAtIndex:kIASKSpecifierChildViewControllerIndex] objectForKey:@"viewController"];
if (targetViewController == nil) {
// the view controller has not been created yet, create it and set it to our viewList array
// create a new dictionary with the new view controller
NSMutableDictionary *newItemDict = [NSMutableDictionary dictionaryWithCapacity:3];
[newItemDict addEntriesFromDictionary: [self.viewList objectAtIndex:kIASKSpecifierChildViewControllerIndex]]; // copy the title and explain strings
targetViewController = [[[self class] alloc] init];
targetViewController.showDoneButton = NO;
targetViewController.settingsStore = self.settingsStore;
targetViewController.delegate = self.delegate;
// add the new view controller to the dictionary and then to the 'viewList' array
[newItemDict setObject:targetViewController forKey:@"viewController"];
[self.viewList replaceObjectAtIndex:kIASKSpecifierChildViewControllerIndex withObject:newItemDict];
[targetViewController release];
// load the view controll back in to push it
targetViewController = [[self.viewList objectAtIndex:kIASKSpecifierChildViewControllerIndex] objectForKey:@"viewController"];
} }
targetViewController.file = specifier.file;
targetViewController.hiddenKeys = self.hiddenKeys; IASKAppSettingsViewController *targetViewController = [[[self class] alloc] init];
targetViewController.title = specifier.title; targetViewController.showDoneButton = NO;
targetViewController.settingsStore = self.settingsStore;
targetViewController.delegate = self.delegate;
targetViewController.file = specifier.file;
targetViewController.hiddenKeys = self.hiddenKeys;
targetViewController.title = specifier.title;
targetViewController.showCreditsFooter = NO; targetViewController.showCreditsFooter = NO;
_currentChildViewController = targetViewController;
[[self navigationController] pushViewController:targetViewController animated:YES]; [[self navigationController] pushViewController:targetViewController animated:YES];
} else if ([[specifier type] isEqualToString:kIASKOpenURLSpecifier]) { } else if ([[specifier type] isEqualToString:kIASKOpenURLSpecifier]) {
[tableView deselectRowAtIndexPath:indexPath animated:YES]; [tableView deselectRowAtIndexPath:indexPath animated:YES];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:specifier.file]]; [[UIApplication sharedApplication] openURL:[NSURL URLWithString:specifier.file]];
} else if ([[specifier type] isEqualToString:kIASKButtonSpecifier]) { } else if ([[specifier type] isEqualToString:kIASKButtonSpecifier]) {
[tableView deselectRowAtIndexPath:indexPath animated:YES]; [tableView deselectRowAtIndexPath:indexPath animated:YES];
if ([self.delegate respondsToSelector:@selector(settingsViewController:buttonTappedForSpecifier:)]) { if ([self.delegate respondsToSelector:@selector(settingsViewController:buttonTappedForSpecifier:)]) {
[self.delegate settingsViewController:self buttonTappedForSpecifier:specifier]; [self.delegate settingsViewController:self buttonTappedForSpecifier:specifier];
} else if ([self.delegate respondsToSelector:@selector(settingsViewController:buttonTappedForKey:)]) { } else if ([self.delegate respondsToSelector:@selector(settingsViewController:buttonTappedForKey:)]) {
// deprecated, provided for backward compatibility // deprecated, provided for backward compatibility
NSLog(@"InAppSettingsKit Warning: -settingsViewController:buttonTappedForKey: is deprecated. Please use -settingsViewController:buttonTappedForSpecifier:"); NSLog(@"InAppSettingsKit Warning: -settingsViewController:buttonTappedForKey: is deprecated. Please use -settingsViewController:buttonTappedForSpecifier:");
[self.delegate settingsViewController:self buttonTappedForKey:[specifier key]]; [self.delegate settingsViewController:self buttonTappedForKey:[specifier key]];
} else { } else {
// legacy code, provided for backward compatibility // legacy code, provided for backward compatibility
// the delegate mechanism above is much cleaner and doesn't leak // the delegate mechanism above is much cleaner and doesn't leak
Class buttonClass = [specifier buttonClass]; Class buttonClass = [specifier buttonClass];
SEL buttonAction = [specifier buttonAction]; SEL buttonAction = [specifier buttonAction];
if ([buttonClass respondsToSelector:buttonAction]) { if ([buttonClass respondsToSelector:buttonAction]) {
[buttonClass performSelector:buttonAction withObject:self withObject:[specifier key]]; #pragma clang diagnostic push
NSLog(@"InAppSettingsKit Warning: Using IASKButtonSpecifier without implementing the delegate method is deprecated"); #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
} [buttonClass performSelector:buttonAction withObject:self withObject:[specifier key]];
} #pragma clang diagnostic pop
NSLog(@"InAppSettingsKit Warning: Using IASKButtonSpecifier without implementing the delegate method is deprecated");
}
}
} else if ([[specifier type] isEqualToString:kIASKMailComposeSpecifier]) { } else if ([[specifier type] isEqualToString:kIASKMailComposeSpecifier]) {
[tableView deselectRowAtIndexPath:indexPath animated:YES]; [tableView deselectRowAtIndexPath:indexPath animated:YES];
if ([MFMailComposeViewController canSendMail]) { if ([MFMailComposeViewController canSendMail]) {
MFMailComposeViewController *mailViewController = [[MFMailComposeViewController alloc] init]; MFMailComposeViewController *mailViewController = [[MFMailComposeViewController alloc] init];
mailViewController.navigationBar.barStyle = self.navigationController.navigationBar.barStyle; mailViewController.navigationBar.barStyle = self.navigationController.navigationBar.barStyle;
mailViewController.navigationBar.tintColor = self.navigationController.navigationBar.tintColor; mailViewController.navigationBar.tintColor = self.navigationController.navigationBar.tintColor;
mailViewController.navigationBar.titleTextAttributes =
self.navigationController.navigationBar.titleTextAttributes;
if ([specifier localizedObjectForKey:kIASKMailComposeSubject]) { if ([specifier localizedObjectForKey:kIASKMailComposeSubject]) {
[mailViewController setSubject:[specifier localizedObjectForKey:kIASKMailComposeSubject]]; [mailViewController setSubject:[specifier localizedObjectForKey:kIASKMailComposeSubject]];
} }
@ -758,7 +705,7 @@ CGRect IASKCGRectSwap(CGRect rect);
isHTML = [[[specifier specifierDict] objectForKey:kIASKMailComposeBodyIsHTML] boolValue]; isHTML = [[[specifier specifierDict] objectForKey:kIASKMailComposeBodyIsHTML] boolValue];
} }
if ([self.delegate respondsToSelector:@selector(settingsViewController:mailComposeBodyForSpecifier:)]) { if ([self.delegate respondsToSelector:@selector(settingsViewController:mailComposeBodyForSpecifier:)]) {
[mailViewController setMessageBody:[self.delegate settingsViewController:self [mailViewController setMessageBody:[self.delegate settingsViewController:self
mailComposeBodyForSpecifier:specifier] isHTML:isHTML]; mailComposeBodyForSpecifier:specifier] isHTML:isHTML];
} }
@ -766,11 +713,11 @@ CGRect IASKCGRectSwap(CGRect rect);
[mailViewController setMessageBody:[specifier localizedObjectForKey:kIASKMailComposeBody] isHTML:isHTML]; [mailViewController setMessageBody:[specifier localizedObjectForKey:kIASKMailComposeBody] isHTML:isHTML];
} }
} }
UIViewController<MFMailComposeViewControllerDelegate> *vc = nil; UIViewController<MFMailComposeViewControllerDelegate> *vc = nil;
if ([self.delegate respondsToSelector:@selector(settingsViewController:viewControllerForMailComposeViewForSpecifier:)]) { if ([self.delegate respondsToSelector:@selector(settingsViewController:viewControllerForMailComposeViewForSpecifier:)]) {
vc = [self.delegate settingsViewController:self viewControllerForMailComposeViewForSpecifier:specifier]; vc = [self.delegate settingsViewController:self viewControllerForMailComposeViewForSpecifier:specifier];
} }
if (vc == nil) { if (vc == nil) {
@ -778,20 +725,10 @@ CGRect IASKCGRectSwap(CGRect rect);
} }
mailViewController.mailComposeDelegate = vc; mailViewController.mailComposeDelegate = vc;
#if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 50000) _currentChildViewController = mailViewController;
//#pragma message "Now that we're iOS5 and up, remove this workaround" [vc presentViewController:mailViewController
#endif animated:YES
if([vc respondsToSelector:@selector(presentViewController:animated:completion:)]) { completion:nil];
[vc presentViewController:mailViewController
animated:YES
completion:nil];
} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[vc presentModalViewController:mailViewController animated:YES];
#pragma clang diagnostic pop
}
[mailViewController release];
} else { } else {
UIAlertView *alert = [[UIAlertView alloc] UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:NSLocalizedString(@"Mail not configured", @"InAppSettingsKit") initWithTitle:NSLocalizedString(@"Mail not configured", @"InAppSettingsKit")
@ -800,10 +737,9 @@ CGRect IASKCGRectSwap(CGRect rect);
cancelButtonTitle:NSLocalizedString(@"OK", @"InAppSettingsKit") cancelButtonTitle:NSLocalizedString(@"OK", @"InAppSettingsKit")
otherButtonTitles:nil]; otherButtonTitles:nil];
[alert show]; [alert show];
[alert release];
} }
} else if ([[specifier type] isEqualToString:kIASKCustomViewSpecifier] && [self.delegate respondsToSelector:@selector(settingsViewController:tableView:didSelectCustomViewSpecifier:)]) { } else if ([[specifier type] isEqualToString:kIASKCustomViewSpecifier] && [self.delegate respondsToSelector:@selector(settingsViewController:tableView:didSelectCustomViewSpecifier:)]) {
[self.delegate settingsViewController:self tableView:tableView didSelectCustomViewSpecifier:specifier]; [self.delegate settingsViewController:self tableView:tableView didSelectCustomViewSpecifier:specifier];
} else { } else {
[tableView deselectRowAtIndexPath:indexPath animated:NO]; [tableView deselectRowAtIndexPath:indexPath animated:NO];
@ -822,21 +758,10 @@ CGRect IASKCGRectSwap(CGRect rect);
mailComposeController:controller mailComposeController:controller
didFinishWithResult:result didFinishWithResult:result
error:error]; error:error];
}
#if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 50000)
//#pragma message "Now that we're iOS5 and up, remove this workaround"
#endif
if([self respondsToSelector:@selector(dismissViewControllerAnimated:completion:)]) {
[self dismissViewControllerAnimated:YES
completion:nil];
} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[self dismissModalViewControllerAnimated:YES];
#pragma clang diagnostic pop
} }
[self dismissViewControllerAnimated:YES
completion:nil];
} }
#pragma mark - #pragma mark -
@ -848,7 +773,7 @@ CGRect IASKCGRectSwap(CGRect rect);
} }
- (void)_textChanged:(id)sender { - (void)_textChanged:(id)sender {
IASKTextField *text = [[(IASKTextField*)sender retain] autorelease]; IASKTextField *text = sender;
[_settingsStore setObject:[text text] forKey:[text key]]; [_settingsStore setObject:[text text] forKey:[text key]];
[[NSNotificationCenter defaultCenter] postNotificationName:kIASKAppSettingChanged [[NSNotificationCenter defaultCenter] postNotificationName:kIASKAppSettingChanged
object:[text key] object:[text key]
@ -884,8 +809,7 @@ static NSDictionary *oldUserDefaults = nil;
} }
} }
} }
[oldUserDefaults release], oldUserDefaults = [currentDict retain]; oldUserDefaults = currentDict;
for (UITableViewCell *cell in self.tableView.visibleCells) { for (UITableViewCell *cell in self.tableView.visibleCells) {
if ([cell isKindOfClass:[IASKPSTextFieldSpecifierViewCell class]] && [((IASKPSTextFieldSpecifierViewCell*)cell).textField isFirstResponder]) { if ([cell isKindOfClass:[IASKPSTextFieldSpecifierViewCell class]] && [((IASKPSTextFieldSpecifierViewCell*)cell).textField isFirstResponder]) {

View file

@ -46,13 +46,6 @@
self.view = webView; self.view = webView;
} }
- (void)dealloc {
[webView release], webView = nil;
[url release], url = nil;
[super dealloc];
}
- (void)viewWillAppear:(BOOL)animated { - (void)viewWillAppear:(BOOL)animated {
[webView loadRequest:[NSURLRequest requestWithURL:self.url]]; [webView loadRequest:[NSURLRequest requestWithURL:self.url]];
} }
@ -102,11 +95,10 @@
NSString *key = [[keyValue objectAtIndex:0] lowercaseString]; NSString *key = [[keyValue objectAtIndex:0] lowercaseString];
NSString *value = [keyValue objectAtIndex:1]; NSString *value = [keyValue objectAtIndex:1];
value = (NSString *)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, value = CFBridgingRelease(CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault,
(CFStringRef)value, (CFStringRef)value,
CFSTR(""), CFSTR(""),
kCFStringEncodingUTF8); kCFStringEncodingUTF8));
[value autorelease];
if ([key isEqualToString:@"subject"]) { if ([key isEqualToString:@"subject"]) {
[mailViewController setSubject:value]; [mailViewController setSubject:value];
@ -133,21 +125,10 @@
} }
[mailViewController setToRecipients:toRecipients]; [mailViewController setToRecipients:toRecipients];
#if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 50000) [self presentViewController:mailViewController
//#pragma message "Now that we're iOS5 and up, remove this workaround" animated:YES
#endif completion:nil];
if([self respondsToSelector:@selector(presentViewController:animated:completion:)]) {
[self presentViewController:mailViewController
animated:YES
completion:nil];
} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[self presentModalViewController:mailViewController animated:YES];
#pragma clang diagnostic pop
}
[mailViewController release];
return NO; return NO;
} }
@ -160,21 +141,8 @@
} }
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error { - (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {
#if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 50000) [self dismissViewControllerAnimated:YES
//#pragma message "Now that we're iOS5 and up, remove this workaround" completion:nil];
#endif
if([self respondsToSelector:@selector(dismissViewControllerAnimated:completion:)]) {
[self dismissViewControllerAnimated:YES
completion:nil];
} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[self dismissModalViewControllerAnimated:YES];
#pragma clang diagnostic pop
}
} }
@end @end

View file

@ -110,17 +110,6 @@
self.tableView = nil; self.tableView = nil;
} }
- (void)dealloc {
[_currentSpecifier release], _currentSpecifier = nil;
[_checkedItem release], _checkedItem = nil;
[_settingsReader release], _settingsReader = nil;
[_settingsStore release], _settingsStore = nil;
[_tableView release], _tableView = nil;
[super dealloc];
}
#pragma mark - #pragma mark -
#pragma mark UITableView delegates #pragma mark UITableView delegates
@ -151,7 +140,7 @@
NSArray *titles = [_currentSpecifier multipleTitles]; NSArray *titles = [_currentSpecifier multipleTitles];
if (!cell) { if (!cell) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCellValue] autorelease]; cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCellValue];
} }
if ([indexPath isEqual:[self checkedItem]]) { if ([indexPath isEqual:[self checkedItem]]) {
@ -197,7 +186,7 @@
#pragma mark Notifications #pragma mark Notifications
- (void)userDefaultsDidChange { - (void)userDefaultsDidChange {
NSIndexPath *oldCheckedItem = [[self.checkedItem retain] autorelease]; NSIndexPath *oldCheckedItem = self.checkedItem;
if(_currentSpecifier) { if(_currentSpecifier) {
[self updateCheckedItem]; [self updateCheckedItem];
} }

View file

@ -94,13 +94,17 @@
#define kIASKMinLabelWidth 97 #define kIASKMinLabelWidth 97
#define kIASKMaxLabelWidth 240 #define kIASKMaxLabelWidth 240
#define kIASKMinValueWidth 35 #define kIASKMinValueWidth 35
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
#define kIASKPaddingLeft (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1 ? 14 : 9)
#else
#define kIASKPaddingLeft 9 #define kIASKPaddingLeft 9
#endif
#define kIASKPaddingRight 10 #define kIASKPaddingRight 10
#define kIASKHorizontalPaddingGroupTitles 19 #define kIASKHorizontalPaddingGroupTitles 19
#define kIASKVerticalPaddingGroupTitles 15 #define kIASKVerticalPaddingGroupTitles 15
#define kIASKLabelFontSize 17 #define kIASKLabelFontSize 17
#define kIASKgrayBlueColor [UIColor colorWithRed:0.318 green:0.4 blue:0.569 alpha:1.0] #define kIASKgrayBlueColor [UIColor colorWithRed:0.318f green:0.4f blue:0.569f alpha:1.f]
#define kIASKMinimumFontSize 12.0f #define kIASKMinimumFontSize 12.0f

View file

@ -28,14 +28,14 @@
applicationBundle:(NSBundle*) bundle { applicationBundle:(NSBundle*) bundle {
self = [super init]; self = [super init];
if (self) { if (self) {
_applicationBundle = [bundle retain]; _applicationBundle = bundle;
NSString* plistFilePath = [self locateSettingsFile: fileName]; NSString* plistFilePath = [self locateSettingsFile: fileName];
_settingsDictionary = [[NSDictionary dictionaryWithContentsOfFile:plistFilePath] retain]; _settingsDictionary = [NSDictionary dictionaryWithContentsOfFile:plistFilePath];
//store the bundle which we'll need later for getting localizations //store the bundle which we'll need later for getting localizations
NSString* settingsBundlePath = [plistFilePath stringByDeletingLastPathComponent]; NSString* settingsBundlePath = [plistFilePath stringByDeletingLastPathComponent];
_settingsBundle = [[NSBundle bundleWithPath:settingsBundlePath] retain]; _settingsBundle = [NSBundle bundleWithPath:settingsBundlePath];
// Look for localization file // Look for localization file
self.localizationTable = [_settingsDictionary objectForKey:@"StringsTable"]; self.localizationTable = [_settingsDictionary objectForKey:@"StringsTable"];
@ -67,22 +67,9 @@
return [self initWithFile:@"Root"]; return [self initWithFile:@"Root"];
} }
- (void)dealloc {
[_localizationTable release], _localizationTable = nil;
[_settingsDictionary release], _settingsDictionary = nil;
[_dataSource release], _dataSource = nil;
[_settingsBundle release], _settingsBundle = nil;
[_hiddenKeys release], _hiddenKeys = nil;
[super dealloc];
}
- (void)setHiddenKeys:(NSSet *)anHiddenKeys { - (void)setHiddenKeys:(NSSet *)anHiddenKeys {
if (_hiddenKeys != anHiddenKeys) { if (_hiddenKeys != anHiddenKeys) {
id old = _hiddenKeys; _hiddenKeys = anHiddenKeys;
_hiddenKeys = [anHiddenKeys retain];
[old release];
if (self.settingsDictionary) { if (self.settingsDictionary) {
[self _reinterpretBundle:self.settingsDictionary]; [self _reinterpretBundle:self.settingsDictionary];
@ -94,7 +81,7 @@
- (void)_reinterpretBundle:(NSDictionary*)settingsBundle { - (void)_reinterpretBundle:(NSDictionary*)settingsBundle {
NSArray *preferenceSpecifiers = [settingsBundle objectForKey:kIASKPreferenceSpecifiers]; NSArray *preferenceSpecifiers = [settingsBundle objectForKey:kIASKPreferenceSpecifiers];
NSInteger sectionCount = -1; NSInteger sectionCount = -1;
NSMutableArray *dataSource = [[[NSMutableArray alloc] init] autorelease]; NSMutableArray *dataSource = [NSMutableArray new];
for (NSDictionary *specifier in preferenceSpecifiers) { for (NSDictionary *specifier in preferenceSpecifiers) {
if ([self.hiddenKeys containsObject:[specifier objectForKey:kIASKKey]]) { if ([self.hiddenKeys containsObject:[specifier objectForKey:kIASKKey]]) {
@ -105,20 +92,17 @@
[newArray addObject:specifier]; [newArray addObject:specifier];
[dataSource addObject:newArray]; [dataSource addObject:newArray];
[newArray release];
sectionCount++; sectionCount++;
} }
else { else {
if (sectionCount == -1) { if (sectionCount == -1) {
NSMutableArray *newArray = [[NSMutableArray alloc] init]; NSMutableArray *newArray = [[NSMutableArray alloc] init];
[dataSource addObject:newArray]; [dataSource addObject:newArray];
[newArray release];
sectionCount++; sectionCount++;
} }
IASKSpecifier *newSpecifier = [[IASKSpecifier alloc] initWithSpecifier:specifier]; IASKSpecifier *newSpecifier = [[IASKSpecifier alloc] initWithSpecifier:specifier];
[(NSMutableArray*)[dataSource objectAtIndex:sectionCount] addObject:newSpecifier]; [(NSMutableArray*)[dataSource objectAtIndex:sectionCount] addObject:newSpecifier];
[newSpecifier release];
} }
} }
[self setDataSource:dataSource]; [self setDataSource:dataSource];

Some files were not shown because too many files have changed in this diff Show more