blob: 494b31a441dee975600f5b2bc244585cd20e5ec0 [file] [log] [blame]
/* Copyright (c) 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if defined(__has_feature) && __has_feature(objc_arc)
#error "This file uses manual reference counting. Compile with -fno-objc-arc"
#endif
#import "GTMHTTPFetcherLogViewController.h"
#if !STRIP_GTM_FETCH_LOGGING && !STRIP_GTM_HTTPLOGVIEWCONTROLLER
#import <objc/runtime.h>
#import "GTMHTTPFetcher.h"
#import "GTMHTTPFetcherLogging.h"
static NSString *const kHTTPLogsCell = @"kGTMHTTPLogsCell";
// A minimal controller will be used to wrap a web view for displaying the
// log files.
@interface GTMHTTPFetcherLoggingWebViewController : UIViewController<UIWebViewDelegate>
- (id)initWithURL:(NSURL *)htmlURL title:(NSString *)title;
@end
#pragma mark - Table View Controller
@interface GTMHTTPFetcherLogViewController ()
@property (nonatomic, copy) void (^callbackBlock)(void);
@end
@implementation GTMHTTPFetcherLogViewController {
NSArray *logsFolderURLs_;
}
@synthesize callbackBlock = callbackBlock_;
- (instancetype)initWithStyle:(UITableViewStyle)style {
self = [super initWithStyle:style];
if (self) {
self.title = @"HTTP Logs";
// Find all folders containing logs.
NSError *error;
NSFileManager *fm = [NSFileManager defaultManager];
NSString *logsFolderPath = [GTMHTTPFetcher loggingDirectory];
NSString *processName = [GTMHTTPFetcher loggingProcessName];
NSURL *logsURL = [NSURL fileURLWithPath:logsFolderPath];
NSMutableArray *mutableURLs =
[[fm contentsOfDirectoryAtURL:logsURL
includingPropertiesForKeys:@[ NSURLCreationDateKey ]
options:0
error:&error] mutableCopy];
// Remove non-log files that lack the process name prefix,
// and remove the "newest" symlink.
NSString *symlinkSuffix = [GTMHTTPFetcher symlinkNameSuffix];
NSIndexSet *nonLogIndexes = [mutableURLs indexesOfObjectsPassingTest:
^BOOL(id obj, NSUInteger idx, BOOL *stop) {
NSString *name = [obj lastPathComponent];
return (![name hasPrefix:processName]
|| [name hasSuffix:symlinkSuffix]);
}];
[mutableURLs removeObjectsAtIndexes:nonLogIndexes];
// Sort to put the newest logs at the top of the list.
[mutableURLs sortUsingComparator:^NSComparisonResult(NSURL *url1,
NSURL *url2) {
NSDate *date1, *date2;
[url1 getResourceValue:&date1 forKey:NSURLCreationDateKey error:NULL];
[url2 getResourceValue:&date2 forKey:NSURLCreationDateKey error:NULL];
return [date2 compare:date1];
}];
logsFolderURLs_ = mutableURLs;
}
return self;
}
- (void)dealloc {
[logsFolderURLs_ release];
[super dealloc];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Avoid silent failure if this was not added to a UINavigationController.
//
// The method +controllerWithTarget:selector: can be used to create a
// temporary UINavigationController.
NSAssert(self.navigationController != nil, @"Need a UINavigationController");
}
#pragma mark -
- (NSString *)shortenedNameForURL:(NSURL *)url {
// Remove "Processname_log_" from the start of the file name.
NSString *name = [url lastPathComponent];
NSString *prefix = [GTMHTTPFetcher processNameLogPrefix];
if ([name hasPrefix:prefix]) {
name = [name substringFromIndex:[prefix length]];
}
return name;
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
return [logsFolderURLs_ count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:kHTTPLogsCell];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:kHTTPLogsCell] autorelease];
[cell.textLabel setAdjustsFontSizeToFitWidth:YES];
}
NSURL *url = [logsFolderURLs_ objectAtIndex:indexPath.row];
cell.textLabel.text = [self shortenedNameForURL:url];
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSURL *folderURL = [logsFolderURLs_ objectAtIndex:indexPath.row];
NSString *htmlName = [GTMHTTPFetcher htmlFileName];
NSURL *htmlURL = [folderURL URLByAppendingPathComponent:htmlName];
// Show the webview controller.
NSString *title = [self shortenedNameForURL:folderURL];
UIViewController *webViewController =
[[[GTMHTTPFetcherLoggingWebViewController alloc] initWithURL:htmlURL
title:title] autorelease];
UINavigationController *navController = [self navigationController];
[navController pushViewController:webViewController animated:YES];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#pragma mark -
+ (UINavigationController *)controllerWithTarget:(id)target
selector:(SEL)selector {
UINavigationController *navController =
[[[UINavigationController alloc] init] autorelease];
GTMHTTPFetcherLogViewController *logViewController =
[[[GTMHTTPFetcherLogViewController alloc] init] autorelease];
UIBarButtonItem *barButtonItem =
[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:logViewController
action:@selector(doneButtonClicked:)] autorelease];
logViewController.navigationItem.leftBarButtonItem = barButtonItem;
// Make a block to capture the callback and nav controller.
void (^block)(void) = ^{
if (target && selector) {
[target performSelector:selector withObject:navController];
}
};
logViewController.callbackBlock = block;
navController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[navController pushViewController:logViewController animated:NO];
return navController;
}
- (void)doneButtonClicked:(UIBarButtonItem *)barButtonItem {
void (^block)() = self.callbackBlock;
block();
self.callbackBlock = nil;
}
@end
#pragma mark - Minimal WebView Controller
@implementation GTMHTTPFetcherLoggingWebViewController {
NSURL *htmlURL_;
}
- (instancetype)initWithURL:(NSURL *)htmlURL
title:(NSString *)title {
self = [super initWithNibName:nil bundle:nil];
if (self) {
self.title = title;
htmlURL_ = [htmlURL retain];
}
return self;
}
- (void)dealloc {
[htmlURL_ release];
[super dealloc];
}
- (void)loadView {
UIWebView *webView = [[UIWebView alloc] init];
webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth
| UIViewAutoresizingFlexibleHeight);
webView.delegate = self;
self.view = webView;
}
- (void)viewDidLoad {
NSURLRequest *request = [NSURLRequest requestWithURL:htmlURL_];
[[self webView] loadRequest:request];
}
- (void)didTapBackButton:(UIButton *)button {
[[self webView] goBack];
}
- (UIWebView *)webView {
return (UIWebView *)self.view;
}
#pragma mark - WebView delegate
- (void)webViewDidFinishLoad:(UIWebView *)webView {
// Instead of the nav controller's back button, provide a simple
// webview back button when it's needed.
BOOL canGoBack = [webView canGoBack];
UIBarButtonItem *backItem = nil;
if (canGoBack) {
// This hides the nav back button.
backItem = [[[UIBarButtonItem alloc] initWithTitle:@"⏎"
style:UIBarButtonItemStylePlain
target:self
action:@selector(didTapBackButton:)] autorelease];
}
self.navigationItem.leftBarButtonItem = backItem;
}
@end
#endif // !STRIP_GTM_FETCH_LOGGING && !STRIP_GTM_HTTPLOGVIEWCONTROLLER