From fad0e1e93e1f2e145970829f81a0c20e42eba09a Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Tue, 5 Nov 2013 00:10:01 +0400 Subject: RevealViewController and small other additions --- Juick.xcodeproj/project.pbxproj | 36 +++++-- Juick/AppDelegate.h | 3 + Juick/AppDelegate.m | 26 ++++- Juick/Juick-Info.plist | 6 +- Juick/Main.storyboard | 81 ---------------- Juick/MasterViewController.h | 13 --- Juick/MasterViewController.m | 168 -------------------------------- Juick/MessagesViewController.h | 14 +++ Juick/MessagesViewController.m | 195 ++++++++++++++++++++++++++++++++++++++ Juick/NSURL+PathParameters.h | 37 ++++++++ Juick/NSURL+PathParameters.m | 173 +++++++++++++++++++++++++++++++++ Juick/RevealPanelViewController.h | 13 +++ Juick/RevealPanelViewController.m | 69 ++++++++++++++ Juick/reveal-icon.png | Bin 0 -> 1118 bytes Juick/reveal-icon@2x.png | Bin 0 -> 1066 bytes Podfile | 1 + Podfile.lock | 3 + 17 files changed, 561 insertions(+), 277 deletions(-) delete mode 100644 Juick/Main.storyboard delete mode 100644 Juick/MasterViewController.h delete mode 100644 Juick/MasterViewController.m create mode 100644 Juick/MessagesViewController.h create mode 100644 Juick/MessagesViewController.m create mode 100644 Juick/NSURL+PathParameters.h create mode 100644 Juick/NSURL+PathParameters.m create mode 100644 Juick/RevealPanelViewController.h create mode 100644 Juick/RevealPanelViewController.m create mode 100644 Juick/reveal-icon.png create mode 100644 Juick/reveal-icon@2x.png diff --git a/Juick.xcodeproj/project.pbxproj b/Juick.xcodeproj/project.pbxproj index 978e6d5..0b5eb79 100644 --- a/Juick.xcodeproj/project.pbxproj +++ b/Juick.xcodeproj/project.pbxproj @@ -14,7 +14,7 @@ 77317BB6181BBE8500D60005 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 77317BB4181BBE8500D60005 /* InfoPlist.strings */; }; 77317BB8181BBE8500D60005 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 77317BB7181BBE8500D60005 /* main.m */; }; 77317BBC181BBE8500D60005 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 77317BBB181BBE8500D60005 /* AppDelegate.m */; }; - 77317BC2181BBE8500D60005 /* MasterViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 77317BC1181BBE8500D60005 /* MasterViewController.m */; }; + 77317BC2181BBE8500D60005 /* MessagesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 77317BC1181BBE8500D60005 /* MessagesViewController.m */; }; 77317BC7181BBE8500D60005 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 77317BC6181BBE8500D60005 /* Images.xcassets */; }; 77317BCE181BBE8500D60005 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77317BCD181BBE8500D60005 /* XCTest.framework */; }; 77317BCF181BBE8500D60005 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77317BAB181BBE8500D60005 /* Foundation.framework */; }; @@ -22,7 +22,10 @@ 77317BD8181BBE8500D60005 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 77317BD6181BBE8500D60005 /* InfoPlist.strings */; }; 77317BDA181BBE8500D60005 /* JuickTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 77317BD9181BBE8500D60005 /* JuickTests.m */; }; 77A0954A181F1F25002BDECD /* Message.m in Sources */ = {isa = PBXBuildFile; fileRef = 77A09549181F1F25002BDECD /* Message.m */; }; - 77A09569181F98D0002BDECD /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 77A09568181F98D0002BDECD /* Main.storyboard */; }; + 77C67EDE182827DB00427098 /* reveal-icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 77C67EDC182827DB00427098 /* reveal-icon.png */; }; + 77C67EDF182827DB00427098 /* reveal-icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 77C67EDD182827DB00427098 /* reveal-icon@2x.png */; }; + 77C67EE21828288C00427098 /* RevealPanelViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 77C67EE11828288C00427098 /* RevealPanelViewController.m */; }; + 77C67EE51828342000427098 /* NSURL+PathParameters.m in Sources */ = {isa = PBXBuildFile; fileRef = 77C67EE41828342000427098 /* NSURL+PathParameters.m */; }; 77D163C2181F048F00401EF0 /* MessageCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 77D163C1181F048F00401EF0 /* MessageCell.m */; }; /* End PBXBuildFile section */ @@ -47,8 +50,8 @@ 77317BB9181BBE8500D60005 /* Juick-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Juick-Prefix.pch"; sourceTree = ""; }; 77317BBA181BBE8500D60005 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 77317BBB181BBE8500D60005 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 77317BC0181BBE8500D60005 /* MasterViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MasterViewController.h; sourceTree = ""; }; - 77317BC1181BBE8500D60005 /* MasterViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MasterViewController.m; sourceTree = ""; }; + 77317BC0181BBE8500D60005 /* MessagesViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MessagesViewController.h; sourceTree = ""; }; + 77317BC1181BBE8500D60005 /* MessagesViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MessagesViewController.m; sourceTree = ""; }; 77317BC6181BBE8500D60005 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 77317BCC181BBE8500D60005 /* JuickTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = JuickTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 77317BCD181BBE8500D60005 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; @@ -57,7 +60,12 @@ 77317BD9181BBE8500D60005 /* JuickTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JuickTests.m; sourceTree = ""; }; 77A09548181F1F25002BDECD /* Message.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Message.h; sourceTree = ""; }; 77A09549181F1F25002BDECD /* Message.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Message.m; sourceTree = ""; }; - 77A09568181F98D0002BDECD /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; + 77C67EDC182827DB00427098 /* reveal-icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "reveal-icon.png"; sourceTree = ""; }; + 77C67EDD182827DB00427098 /* reveal-icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "reveal-icon@2x.png"; sourceTree = ""; }; + 77C67EE01828288C00427098 /* RevealPanelViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RevealPanelViewController.h; sourceTree = ""; }; + 77C67EE11828288C00427098 /* RevealPanelViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RevealPanelViewController.m; sourceTree = ""; }; + 77C67EE31828342000427098 /* NSURL+PathParameters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURL+PathParameters.h"; sourceTree = ""; }; + 77C67EE41828342000427098 /* NSURL+PathParameters.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURL+PathParameters.m"; sourceTree = ""; }; 77D163C0181F048F00401EF0 /* MessageCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessageCell.h; sourceTree = ""; }; 77D163C1181F048F00401EF0 /* MessageCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MessageCell.m; sourceTree = ""; }; AD52EBAFFD6B4395B342F246 /* Pods-Juick.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Juick.xcconfig"; path = "Pods/Pods-Juick.xcconfig"; sourceTree = ""; }; @@ -124,17 +132,22 @@ 77317BB1181BBE8500D60005 /* Juick */ = { isa = PBXGroup; children = ( + 77C67EE31828342000427098 /* NSURL+PathParameters.h */, + 77C67EE41828342000427098 /* NSURL+PathParameters.m */, + 77C67EDC182827DB00427098 /* reveal-icon.png */, + 77C67EDD182827DB00427098 /* reveal-icon@2x.png */, 77317BBA181BBE8500D60005 /* AppDelegate.h */, 77317BBB181BBE8500D60005 /* AppDelegate.m */, - 77317BC0181BBE8500D60005 /* MasterViewController.h */, - 77317BC1181BBE8500D60005 /* MasterViewController.m */, + 77317BC0181BBE8500D60005 /* MessagesViewController.h */, + 77317BC1181BBE8500D60005 /* MessagesViewController.m */, 77317BC6181BBE8500D60005 /* Images.xcassets */, 77317BB2181BBE8500D60005 /* Supporting Files */, 77D163C0181F048F00401EF0 /* MessageCell.h */, 77D163C1181F048F00401EF0 /* MessageCell.m */, 77A09548181F1F25002BDECD /* Message.h */, 77A09549181F1F25002BDECD /* Message.m */, - 77A09568181F98D0002BDECD /* Main.storyboard */, + 77C67EE01828288C00427098 /* RevealPanelViewController.h */, + 77C67EE11828288C00427098 /* RevealPanelViewController.m */, ); path = Juick; sourceTree = ""; @@ -246,9 +259,10 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 77A09569181F98D0002BDECD /* Main.storyboard in Resources */, + 77C67EDF182827DB00427098 /* reveal-icon@2x.png in Resources */, 77317BC7181BBE8500D60005 /* Images.xcassets in Resources */, 77317BB6181BBE8500D60005 /* InfoPlist.strings in Resources */, + 77C67EDE182827DB00427098 /* reveal-icon.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -303,7 +317,9 @@ 77D163C2181F048F00401EF0 /* MessageCell.m in Sources */, 77317BBC181BBE8500D60005 /* AppDelegate.m in Sources */, 77A0954A181F1F25002BDECD /* Message.m in Sources */, - 77317BC2181BBE8500D60005 /* MasterViewController.m in Sources */, + 77317BC2181BBE8500D60005 /* MessagesViewController.m in Sources */, + 77C67EE21828288C00427098 /* RevealPanelViewController.m in Sources */, + 77C67EE51828342000427098 /* NSURL+PathParameters.m in Sources */, 77317BB8181BBE8500D60005 /* main.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Juick/AppDelegate.h b/Juick/AppDelegate.h index ae4c86a..087b6fd 100644 --- a/Juick/AppDelegate.h +++ b/Juick/AppDelegate.h @@ -8,8 +8,11 @@ #import +@class SWRevealViewController; + @interface AppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; +@property (strong, nonatomic) SWRevealViewController *viewController; @end diff --git a/Juick/AppDelegate.m b/Juick/AppDelegate.m index 23cef5e..3fa3030 100644 --- a/Juick/AppDelegate.m +++ b/Juick/AppDelegate.m @@ -7,12 +7,36 @@ // #import "AppDelegate.h" -#import "MasterViewController.h" +#import "MessagesViewController.h" +#import "RevealPanelViewController.h" +#import "SWRevealViewController.h" @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + // style the navigation bar + UIColor* navColor = [UIColor colorWithRed:44/255.0f green:44/255.0f blue:44/255.0f alpha:1]; + [[UINavigationBar appearance] setBarTintColor:navColor]; + [[UINavigationBar appearance] setTintColor:[UIColor colorWithRed:153/255.0f green:154/255.0f blue:153/255.0f alpha:1]]; + [[UINavigationBar appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName: [UIColor colorWithRed:153/255.0f green:154/255.0f blue:153/255.0f alpha:1]}]; + + // make the status bar white + [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent; + + MessagesViewController *messages = [[MessagesViewController alloc] initWithURL:[NSURL URLWithString:@"https://api.juick.com/messages"]]; + RevealPanelViewController *rear = [[RevealPanelViewController alloc] init]; + + UINavigationController *main = [[UINavigationController alloc] initWithRootViewController:messages]; + UINavigationController *rearNav = [[UINavigationController alloc] initWithRootViewController:rear]; + + SWRevealViewController *reveal = [[SWRevealViewController alloc] initWithRearViewController:rearNav frontViewController:main]; + self.viewController = reveal; + + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + self.window.rootViewController = reveal; + [self.window makeKeyAndVisible]; + return YES; } diff --git a/Juick/Juick-Info.plist b/Juick/Juick-Info.plist index f23f598..d651337 100644 --- a/Juick/Juick-Info.plist +++ b/Juick/Juick-Info.plist @@ -24,10 +24,6 @@ 1.0 LSRequiresIPhoneOS - NSMainNibFile~ipad - Main-iPad - UIMainStoryboardFile - Main UIRequiredDeviceCapabilities armv7 @@ -48,5 +44,7 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + UIViewControllerBasedStatusBarAppearance + diff --git a/Juick/Main.storyboard b/Juick/Main.storyboard deleted file mode 100644 index cac2c7f..0000000 --- a/Juick/Main.storyboard +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Juick/MasterViewController.h b/Juick/MasterViewController.h deleted file mode 100644 index 5e92717..0000000 --- a/Juick/MasterViewController.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// MasterViewController.h -// Juick -// -// Created by Vitaly Takmazov on 26.10.13. -// Copyright (c) 2013 com.juick. All rights reserved. -// - -#import - -@interface MasterViewController : UITableViewController -- (void) refreshData:(UIRefreshControl *)refresh; -@end diff --git a/Juick/MasterViewController.m b/Juick/MasterViewController.m deleted file mode 100644 index 4ed8df1..0000000 --- a/Juick/MasterViewController.m +++ /dev/null @@ -1,168 +0,0 @@ -// -// MasterViewController.m -// Juick -// -// Created by Vitaly Takmazov on 26.10.13. -// Copyright (c) 2013 com.juick. All rights reserved. -// - -#import "MasterViewController.h" - -#import "MessageCell.h" - -#import "Message.h" - -static NSString *CellIdentifier = @"MessageCell"; - -@interface MasterViewController (); - -@property(nonatomic, strong) NSMutableArray *messages; -@property(nonatomic, assign) Boolean dataLoading; - -@end - -@implementation MasterViewController - -- (void) refreshData:(UIRefreshControl *)refresh { - [self.messages removeAllObjects]; - [self.tableView reloadData]; - NSURL *url = [NSURL URLWithString:@"https://api.juick.com/messages"]; - - NSArray *next = [Message pullNextFromURL:url]; - int64_t delayInSeconds = 2.0; - dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (delayInSeconds * NSEC_PER_SEC)); - dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ - [self.tableView beginUpdates]; - CGPoint offset = self.tableView.contentOffset; - for (int i = 0; i < [next count]; i++) { - [self.messages addObject:[next objectAtIndex:i]]; - [self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:self.messages.count-1 inSection:0]] withRowAnimation:UITableViewRowAnimationNone]; - } - [self.tableView setContentOffset:offset animated:NO]; - [self.tableView endUpdates]; - [refresh endRefreshing]; - }); -} - -- (void)scrollViewDidScroll:(UIScrollView *)scrollView { - CGPoint pos = scrollView.contentOffset; - CGFloat contentHeight = scrollView.contentSize.height - scrollView.contentSize.height / 3; - if (pos.y >= contentHeight && !self.dataLoading) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ - self.dataLoading = YES; - Message * lastMessage = [self.messages lastObject]; - NSArray *next = [Message pullNextFromURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://api.juick.com/messages?before_mid=%@", lastMessage.MID]]]; - int64_t delayInSeconds = 2.0; - dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (delayInSeconds * NSEC_PER_SEC)); - dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ - [self.tableView beginUpdates]; - for (int i = 0; i < [next count]; i++) { - [self.messages addObject:[next objectAtIndex:i]]; - [self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:self.messages.count-1 inSection:0]] withRowAnimation:UITableViewRowAnimationNone]; - } - [self.tableView setContentOffset:pos animated:NO]; - [self.tableView endUpdates]; - self.dataLoading = NO; - }); - }); - - } -} - -- (void)viewDidLoad -{ - [super viewDidLoad]; - self.dataLoading = NO; - self.title = @"Messages"; - self.messages = [NSMutableArray array]; - UIRefreshControl *refresh = [[UIRefreshControl alloc] init]; - [refresh addTarget:self action:@selector(refreshData:) forControlEvents:UIControlEventValueChanged]; - self.refreshControl = refresh; - - //UINib *cellNib = [UINib nibWithNibName:@"MessageCell" bundle:nil]; - //[self.tableView registerNib:cellNib forCellReuseIdentifier:@"MessageCell"]; - [self.tableView registerClass:[MessageCell class] forCellReuseIdentifier:CellIdentifier]; - -} - -- (void)viewDidAppear:(BOOL)animated -{ - [super viewDidAppear:animated]; - - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(contentSizeCategoryChanged:) - name:UIContentSizeCategoryDidChangeNotification - object:nil]; -} - -- (void)viewDidDisappear:(BOOL)animated -{ - [super viewDidDisappear:animated]; - - [[NSNotificationCenter defaultCenter] removeObserver:self - name:UIContentSizeCategoryDidChangeNotification - object:nil]; -} - -- (void)didReceiveMemoryWarning -{ - [super didReceiveMemoryWarning]; - // Dispose of any resources that can be recreated. -} - -- (void)contentSizeCategoryChanged:(NSNotification *)notification -{ - [self.tableView reloadData]; -} - -- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { - return 1; -} - -- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - return _messages.count; -} - -- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - MessageCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; - [cell updateFonts]; - Message *msg = [_messages objectAtIndex:indexPath.row]; - [cell.avatar setImage:[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://i.juick.com/as/%@.png", msg.userID]]]]]; - cell.titleLabel.text = msg.user; - cell.bodyLabel.text = msg.text; - [cell setNeedsUpdateConstraints]; - return cell; -} - -- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath -{ - - - MessageCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; - - [cell updateFonts]; - - Message *msg = [_messages objectAtIndex:indexPath.row]; - [cell.avatar setImage:[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://i.juick.com/as/%@.png", msg.userID]]]]]; - cell.titleLabel.text = msg.user; - cell.bodyLabel.text = msg.text; - - cell.bodyLabel.preferredMaxLayoutWidth = tableView.bounds.size.width - (kLabelHorizontalInsets * 2.0f); - - [cell setNeedsUpdateConstraints]; - [cell updateConstraintsIfNeeded]; - [cell.contentView setNeedsLayout]; - [cell.contentView layoutIfNeeded]; - - CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; - - return height; -} - -- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath -{ - return 100.0f; -} - - -@end diff --git a/Juick/MessagesViewController.h b/Juick/MessagesViewController.h new file mode 100644 index 0000000..ceff611 --- /dev/null +++ b/Juick/MessagesViewController.h @@ -0,0 +1,14 @@ +// +// MasterViewController.h +// Juick +// +// Created by Vitaly Takmazov on 26.10.13. +// Copyright (c) 2013 com.juick. All rights reserved. +// + +#import + +@interface MessagesViewController : UITableViewController +- (id)initWithURL:(NSURL *)messagesURL; +- (void) refreshData:(UIRefreshControl *)refresh; +@end diff --git a/Juick/MessagesViewController.m b/Juick/MessagesViewController.m new file mode 100644 index 0000000..19eebf4 --- /dev/null +++ b/Juick/MessagesViewController.m @@ -0,0 +1,195 @@ +// +// MasterViewController.m +// Juick +// +// Created by Vitaly Takmazov on 26.10.13. +// Copyright (c) 2013 com.juick. All rights reserved. +// + +#import "SWRevealViewController.h" + +#import "MessagesViewController.h" + +#import "MessageCell.h" + +#import "Message.h" + +#import "NSURL+PathParameters.h" + +static NSString *CellIdentifier = @"MessageCell"; + +@interface MessagesViewController (); + +@property(nonatomic, strong) NSMutableArray *messages; +@property(nonatomic, assign) Boolean dataLoading; +@property(nonatomic, strong) NSURL *url; + +@end + +@implementation MessagesViewController + +- (id)initWithURL:(NSURL *)messagesURL +{ + self = [super init]; + if (self) { + self.url = messagesURL; + } + return self; +} + +- (void) refreshData:(UIRefreshControl *)refresh { + [self.messages removeAllObjects]; + [self.tableView reloadData]; + + NSArray *next = [Message pullNextFromURL:self.url]; + int64_t delayInSeconds = 1.0; + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (delayInSeconds * NSEC_PER_SEC)); + dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ + [self.tableView beginUpdates]; + CGPoint offset = self.tableView.contentOffset; + for (int i = 0; i < [next count]; i++) { + [self.messages addObject:[next objectAtIndex:i]]; + [self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:self.messages.count-1 inSection:0]] withRowAnimation:UITableViewRowAnimationNone]; + } + [self.tableView setContentOffset:offset animated:NO]; + [self.tableView endUpdates]; + [refresh endRefreshing]; + }); +} + +- (UIStatusBarStyle)preferredStatusBarStyle +{ + return UIStatusBarStyleLightContent; +} + +- (void)scrollViewDidScroll:(UIScrollView *)scrollView { + CGPoint pos = scrollView.contentOffset; + CGFloat contentHeight = scrollView.contentSize.height - scrollView.contentSize.height / 3; + if (pos.y >= contentHeight && !self.dataLoading) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + self.dataLoading = YES; + Message * lastMessage = [self.messages lastObject]; + NSArray *next = [Message pullNextFromURL:[self.url URLByAppendingParameters:[NSDictionary dictionaryWithObjectsAndKeys:lastMessage.MID, @"before_mid", nil]]]; + int64_t delayInSeconds = 1.0; + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (delayInSeconds * NSEC_PER_SEC)); + dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ + [self.tableView beginUpdates]; + for (int i = 0; i < [next count]; i++) { + [self.messages addObject:[next objectAtIndex:i]]; + [self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:self.messages.count-1 inSection:0]] withRowAnimation:UITableViewRowAnimationNone]; + } + [self.tableView setContentOffset:pos animated:NO]; + [self.tableView endUpdates]; + self.dataLoading = NO; + }); + }); + + } +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + self.dataLoading = NO; + self.title = @"Discover"; + [self.view setBackgroundColor:[UIColor colorWithRed:238/255.0f green:238/255.0f blue:229/255.0f alpha:1.0f]]; + SWRevealViewController *revealController = [self revealViewController]; + [self.navigationController.navigationBar addGestureRecognizer:revealController.panGestureRecognizer]; + UIBarButtonItem *revealButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"reveal-icon.png"] + style:UIBarButtonItemStyleBordered target:revealController action:@selector(revealToggle:)]; + + self.navigationItem.leftBarButtonItem = revealButtonItem; + self.messages = [NSMutableArray array]; + UIRefreshControl *refresh = [[UIRefreshControl alloc] init]; + [refresh addTarget:self action:@selector(refreshData:) forControlEvents:UIControlEventValueChanged]; + self.refreshControl = refresh; + + //UINib *cellNib = [UINib nibWithNibName:@"MessageCell" bundle:nil]; + //[self.tableView registerNib:cellNib forCellReuseIdentifier:@"MessageCell"]; + [self.tableView registerClass:[MessageCell class] forCellReuseIdentifier:CellIdentifier]; + +} + +- (void)viewDidAppear:(BOOL)animated +{ + [super viewDidAppear:animated]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(contentSizeCategoryChanged:) + name:UIContentSizeCategoryDidChangeNotification + object:nil]; +} + +- (void)viewDidDisappear:(BOOL)animated +{ + [super viewDidDisappear:animated]; + + [[NSNotificationCenter defaultCenter] removeObserver:self + name:UIContentSizeCategoryDidChangeNotification + object:nil]; +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +- (void)contentSizeCategoryChanged:(NSNotification *)notification +{ + [self.tableView reloadData]; +} + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return _messages.count; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + MessageCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; + [cell updateFonts]; + Message *msg = [_messages objectAtIndex:indexPath.row]; + [cell.avatar setImage:[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://i.juick.com/as/%@.png", msg.userID]]]]]; + cell.titleLabel.text = msg.user; + cell.titleLabel.textColor = [UIColor colorWithRed:0 green:102/255.0f blue:153/255.0f alpha:1.0f]; + cell.bodyLabel.text = msg.text; + [cell setBackgroundColor:[UIColor whiteColor]]; + [cell setNeedsUpdateConstraints]; + return cell; +} + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath +{ + + + MessageCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; + + [cell updateFonts]; + + Message *msg = [_messages objectAtIndex:indexPath.row]; + [cell.avatar setImage:[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://i.juick.com/as/%@.png", msg.userID]]]]]; + cell.titleLabel.text = msg.user; + cell.bodyLabel.text = msg.text; + + cell.bodyLabel.preferredMaxLayoutWidth = tableView.bounds.size.width - (kLabelHorizontalInsets * 2.0f); + + [cell setNeedsUpdateConstraints]; + [cell updateConstraintsIfNeeded]; + [cell.contentView setNeedsLayout]; + [cell.contentView layoutIfNeeded]; + + CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; + + return height; +} + +- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath +{ + return 100.0f; +} + + +@end diff --git a/Juick/NSURL+PathParameters.h b/Juick/NSURL+PathParameters.h new file mode 100644 index 0000000..73fc004 --- /dev/null +++ b/Juick/NSURL+PathParameters.h @@ -0,0 +1,37 @@ +// +// NSURL+PathParameters.h +// +// Created by Johan Kool on 27/9/2011. +// Copyright 2011 Koolistov Pte. Ltd. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// * Neither the name of KOOLISTOV PTE. LTD. nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific prior written +// permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +// OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + + +#import + +@interface NSURL (PathParameters) + +- (NSURL *)URLByReplacingPathWithPath:(NSString *)path; +- (NSURL *)URLByAppendingPathWithRelativePath:(NSString *)path; +- (NSURL *)URLByAppendingParameters:(NSDictionary *)parameters; +- (NSURL *)URLByAppendingParameterName:(NSString *)parameter value:(id)value; + +@end diff --git a/Juick/NSURL+PathParameters.m b/Juick/NSURL+PathParameters.m new file mode 100644 index 0000000..83a55bb --- /dev/null +++ b/Juick/NSURL+PathParameters.m @@ -0,0 +1,173 @@ +// +// NSURL+PathParameters.m +// +// Created by Johan Kool on 27/9/2011. +// Copyright 2011 Koolistov Pte. Ltd. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// * Neither the name of KOOLISTOV PTE. LTD. nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific prior written +// permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +// OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#import "NSURL+PathParameters.h" + +@interface NSString (URLParameters) + +- (NSString *)stringByEscapingForURLArgument; + +@end + +@implementation NSString (URLParameters) + +- (NSString *)stringByEscapingForURLArgument { + // Encode all the reserved characters, per RFC 3986 () + NSString *escapedString = (__bridge NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, + (CFStringRef)self, + NULL, + (CFStringRef)@"!*'\"();:@&=+$,/?%#[] ", + kCFStringEncodingUTF8); + return [escapedString copy]; +} + +@end + +@implementation NSURL (PathParameters) + +- (NSURL *)URLByReplacingPathWithPath:(NSString *)path { + // scheme://username:password@domain:port/path?query_string#fragment_id + + // Chop off path, query and fragment from absoluteString, then add new path and put back query and fragment + + NSString *absoluteString = [self absoluteString]; + NSUInteger endIndex = [absoluteString length]; + + NSString *fragment = [self fragment]; + if (fragment) { + endIndex -= [fragment length]; + endIndex--; // The # character + } + + NSString *query = [self query]; + if (query) { + endIndex -= [query length]; + endIndex--; // The ? character + } + + // Check if the last character of the path is a slash (range must be valid as endIndex must be smaller or equal to length) + BOOL trailingSlashOnPath = [[absoluteString substringWithRange:NSMakeRange(endIndex - 1, 1)] isEqualToString:@"/"]; + + NSString *originalPath = [self path]; // This method strips any trailing slash "/" + if (originalPath) { + endIndex -= [originalPath length]; + if (trailingSlashOnPath && [originalPath length] > 1) { // Don't get confused with the starting slash + endIndex--; + } + } + + absoluteString = [absoluteString substringToIndex:endIndex]; + absoluteString = [absoluteString stringByAppendingString:path]; + if (query) { + absoluteString = [absoluteString stringByAppendingString:@"?"]; + absoluteString = [absoluteString stringByAppendingString:query]; + } + if (fragment) { + absoluteString = [absoluteString stringByAppendingString:@"#"]; + absoluteString = [absoluteString stringByAppendingString:fragment]; + } + + return [NSURL URLWithString:absoluteString]; +} + +- (NSURL *)URLByAppendingPathWithRelativePath:(NSString *)path { + NSString *originalPath = [self path]; + NSString *combinedPath = [[originalPath stringByAppendingPathComponent:path] stringByStandardizingPath]; + // Don't standardize away a trailing slash + if ([path length] > 1 && [path hasSuffix:@"/"]) { + combinedPath = [combinedPath stringByAppendingString:@"/"]; + } + return [self URLByReplacingPathWithPath:combinedPath]; +} + +- (NSURL *)URLByAppendingParameters:(NSDictionary *)parameters { + NSMutableString *query = [[self query] mutableCopy]; + + if (!query) { + query = [NSMutableString stringWithString:@""]; + } + + // Sort parameters to be appended so that our solution is stable (and testable) + NSArray *parameterNames = [parameters allKeys]; + parameterNames = [parameterNames sortedArrayUsingSelector:@selector(compare:)]; + + for (NSString *parameterName in parameterNames) { + id value = [parameters objectForKey:parameterName]; + NSAssert3([parameterName isKindOfClass:[NSString class]], @"Got '%@' of type %@ as key for parameter with value '%@'. Expected an NSString.", parameterName, NSStringFromClass([parameterName class]), value); + + // The value needs to be an NSString, or be able to give us an NSString + if (![value isKindOfClass:[NSString class]]) { + if ([value respondsToSelector:@selector(stringValue)]) { + value = [value stringValue]; + } else { + // Fallback to simply giving the description + value = [value description]; + } + } + + if ([query length] == 0) { + [query appendFormat:@"%@=%@", [parameterName stringByEscapingForURLArgument], [value stringByEscapingForURLArgument]]; + } else { + [query appendFormat:@"&%@=%@", [parameterName stringByEscapingForURLArgument], [value stringByEscapingForURLArgument]]; + } + } + + // scheme://username:password@domain:port/path?query_string#fragment_id + + // Chop off query and fragment from absoluteString, then add new query and put back fragment + + NSString *absoluteString = [self absoluteString]; + NSUInteger endIndex = [absoluteString length]; + + NSString *fragment = [self fragment]; + if (fragment) { + endIndex -= [fragment length]; + endIndex--; // The # character + } + + NSString *originalQuery = [self query]; + if (originalQuery) { + endIndex -= [originalQuery length]; + endIndex--; // The ? character + } + + absoluteString = [absoluteString substringToIndex:endIndex]; + absoluteString = [absoluteString stringByAppendingString:@"?"]; + absoluteString = [absoluteString stringByAppendingString:query]; + if (fragment) { + absoluteString = [absoluteString stringByAppendingString:@"#"]; + absoluteString = [absoluteString stringByAppendingString:fragment]; + } + + return [NSURL URLWithString:absoluteString]; +} + +- (NSURL *)URLByAppendingParameterName:(NSString *)parameter value:(id)value { + return [self URLByAppendingParameters:[NSDictionary dictionaryWithObjectsAndKeys:value, parameter, nil]]; +} + + +@end diff --git a/Juick/RevealPanelViewController.h b/Juick/RevealPanelViewController.h new file mode 100644 index 0000000..a8196fe --- /dev/null +++ b/Juick/RevealPanelViewController.h @@ -0,0 +1,13 @@ +// +// RevealPanelViewController.h +// Juick +// +// Created by Vitaly Takmazov on 04.11.13. +// Copyright (c) 2013 com.juick. All rights reserved. +// + +#import + +@interface RevealPanelViewController : UITableViewController + +@end diff --git a/Juick/RevealPanelViewController.m b/Juick/RevealPanelViewController.m new file mode 100644 index 0000000..3381e28 --- /dev/null +++ b/Juick/RevealPanelViewController.m @@ -0,0 +1,69 @@ +// +// RevealPanelViewController.m +// Juick +// +// Created by Vitaly Takmazov on 04.11.13. +// Copyright (c) 2013 com.juick. All rights reserved. +// + +#import "RevealPanelViewController.h" + +@interface RevealPanelViewController () + +@end + +@implementation RevealPanelViewController + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + // Custom initialization + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + self.title = @"Juick"; + [self.view setBackgroundColor:[UIColor colorWithRed:238/255.0f green:238/255.0f blue:229/255.0f alpha:1.0f]]; +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 1; +} + +- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return 4; +} + +- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + static NSString *cellIdentifier = @"MenuCell"; + UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; + NSInteger row = indexPath.row; + if (cell == nil) { + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; + [cell setBackgroundColor:[UIColor colorWithRed:236/255.0f green:237/255.0f blue:227/255.0f alpha:1]]; + cell.textLabel.textColor = [UIColor colorWithRed:0 green:102/255.0f blue:153/255.0f alpha:1.0f]; + } + if (row == 0) { + cell.textLabel.text = @"My feed"; + } else if (row == 1) { + cell.textLabel.text = @"Popular"; + } else if (row == 2) { + cell.textLabel.text = @"Discover"; + } else if (row == 3) { + cell.textLabel.text = @"Images"; + } + return cell; +} + +@end diff --git a/Juick/reveal-icon.png b/Juick/reveal-icon.png new file mode 100644 index 0000000..4a4d467 Binary files /dev/null and b/Juick/reveal-icon.png differ diff --git a/Juick/reveal-icon@2x.png b/Juick/reveal-icon@2x.png new file mode 100644 index 0000000..08dc402 Binary files /dev/null and b/Juick/reveal-icon@2x.png differ diff --git a/Podfile b/Podfile index b17b80a..f254f2d 100644 --- a/Podfile +++ b/Podfile @@ -5,6 +5,7 @@ target "Juick" do pod 'MWFeedParser' pod 'TTTAttributedLabel' pod 'Masonry' +pod 'SWRevealViewController' end target "JuickTests" do diff --git a/Podfile.lock b/Podfile.lock index b43bda3..9c2ff0f 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -9,16 +9,19 @@ PODS: - MWFeedParser/NSDate+InternetDateTime (0.0.1) - MWFeedParser/NSString+HTML (0.0.1) - MWFeedParser/NSString+XMLEntities (0.0.1) + - SWRevealViewController (1.0.8) - TTTAttributedLabel (1.7.1) DEPENDENCIES: - Masonry - MWFeedParser + - SWRevealViewController - TTTAttributedLabel SPEC CHECKSUMS: Masonry: 73df2f346bd1a0044dc9de969aa45aea2f8a9bd8 MWFeedParser: 2ca0852fac352f8333d5f46fdd4b583b921e0c4e + SWRevealViewController: 5688d9d017e228c9edd92db359f670d8c47ab8e6 TTTAttributedLabel: e504133915a9b11de63cb470ffa2790383a3eb23 COCOAPODS: 0.27.1 -- cgit v1.2.3