From 033f9053ada0a7f2a9ef7e6652746cd3cbb8f300 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sat, 29 Sep 2012 16:15:01 -0400 Subject: Integrated multi-line SMS-style text box for chat pane. Added a tableView for chat messages. --- Classes/ChatViewController.h | 23 ++ Classes/ChatViewController.m | 210 ++++++++++ Classes/ChatViewController.xib | 150 +++++++ Classes/RootViewController.h | 2 +- Classes/RootViewController.m | 14 +- NearMe.xcodeproj/project.pbxproj | 70 ++++ README.md | 1 + Resources/MessageEntryBackground.png | Bin 0 -> 181 bytes Resources/MessageEntryBackground@2x.png | Bin 0 -> 274 bytes Resources/MessageEntryInputField.png | Bin 0 -> 1356 bytes Resources/MessageEntryInputField@2x.png | Bin 0 -> 3177 bytes Resources/MessageEntrySendButton.png | Bin 0 -> 1037 bytes Resources/MessageEntrySendButton@2x.png | Bin 0 -> 2466 bytes Resources/MessageEntrySendButtonPressed.png | Bin 0 -> 1008 bytes Resources/MessageEntrySendButtonPressed@2x.png | Bin 0 -> 2365 bytes Vendor/HPGrowingTextView.h | 107 +++++ Vendor/HPGrowingTextView.m | 550 +++++++++++++++++++++++++ Vendor/HPTextViewInternal.h | 34 ++ Vendor/HPTextViewInternal.m | 98 +++++ iPhone/AppDelegate_iPhone.m | 5 +- 20 files changed, 1261 insertions(+), 3 deletions(-) create mode 100644 Classes/ChatViewController.h create mode 100644 Classes/ChatViewController.m create mode 100644 Classes/ChatViewController.xib create mode 100644 Resources/MessageEntryBackground.png create mode 100644 Resources/MessageEntryBackground@2x.png create mode 100644 Resources/MessageEntryInputField.png create mode 100644 Resources/MessageEntryInputField@2x.png create mode 100644 Resources/MessageEntrySendButton.png create mode 100644 Resources/MessageEntrySendButton@2x.png create mode 100644 Resources/MessageEntrySendButtonPressed.png create mode 100644 Resources/MessageEntrySendButtonPressed@2x.png create mode 100644 Vendor/HPGrowingTextView.h create mode 100644 Vendor/HPGrowingTextView.m create mode 100644 Vendor/HPTextViewInternal.h create mode 100644 Vendor/HPTextViewInternal.m diff --git a/Classes/ChatViewController.h b/Classes/ChatViewController.h new file mode 100644 index 0000000..ee52715 --- /dev/null +++ b/Classes/ChatViewController.h @@ -0,0 +1,23 @@ +// +// ChatViewController.h +// NearMe +// +// Created by TW on 9/29/12. +// Copyright 2012 __MyCompanyName__. All rights reserved. +// + +#import +#import "HPGrowingTextView.h" + + +@interface ChatViewController : UIViewController { + UITableView *chatTableView; + UIView *containerView; + HPGrowingTextView *textView; +} + +@property (nonatomic, retain) UITableView *chatTableView; + +-(void)resignTextView; + +@end diff --git a/Classes/ChatViewController.m b/Classes/ChatViewController.m new file mode 100644 index 0000000..aee79c8 --- /dev/null +++ b/Classes/ChatViewController.m @@ -0,0 +1,210 @@ +// +// ChatViewController.m +// NearMe +// +// Created by TW on 9/29/12. +// Copyright 2012 __MyCompanyName__. All rights reserved. +// + +#import "ChatViewController.h" + + +@implementation ChatViewController + +@synthesize chatTableView = _chatTableView; + +-(id)init +{ + self = [super init]; + if(self){ + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(keyboardWillShow:) + name:UIKeyboardWillShowNotification + object:nil]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(keyboardWillHide:) + name:UIKeyboardWillHideNotification + object:nil]; + } + + return self; +} + + + +// Implement loadView to create a view hierarchy programmatically, without using a nib. +- (void)loadView { + self.view = [[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]; + self.view.backgroundColor = [UIColor colorWithRed:219.0f/255.0f green:226.0f/255.0f blue:237.0f/255.0f alpha:1]; + + chatTableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; + [self.view addSubview:chatTableView]; + + containerView = [[UIView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height - 40, 320, 40)]; + + textView = [[HPGrowingTextView alloc] initWithFrame:CGRectMake(6, 3, 240, 40)]; + textView.contentInset = UIEdgeInsetsMake(0, 5, 0, 5); + + textView.minNumberOfLines = 1; + textView.maxNumberOfLines = 6; + textView.returnKeyType = UIReturnKeyGo; //just as an example + textView.font = [UIFont systemFontOfSize:15.0f]; + textView.delegate = self; + textView.internalTextView.scrollIndicatorInsets = UIEdgeInsetsMake(5, 0, 5, 0); + textView.backgroundColor = [UIColor whiteColor]; + + // textView.text = @"test\n\ntest"; + // textView.animateHeightChange = NO; //turns off animation + + [self.view addSubview:containerView]; + + UIImage *rawEntryBackground = [UIImage imageNamed:@"MessageEntryInputField.png"]; + UIImage *entryBackground = [rawEntryBackground stretchableImageWithLeftCapWidth:13 topCapHeight:22]; + UIImageView *entryImageView = [[[UIImageView alloc] initWithImage:entryBackground] autorelease]; + entryImageView.frame = CGRectMake(5, 0, 248, 40); + entryImageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; + + UIImage *rawBackground = [UIImage imageNamed:@"MessageEntryBackground.png"]; + UIImage *background = [rawBackground stretchableImageWithLeftCapWidth:13 topCapHeight:22]; + UIImageView *imageView = [[[UIImageView alloc] initWithImage:background] autorelease]; + imageView.frame = CGRectMake(0, 0, containerView.frame.size.width, containerView.frame.size.height); + imageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; + + textView.autoresizingMask = UIViewAutoresizingFlexibleWidth; + + // view hierachy + [containerView addSubview:imageView]; + [containerView addSubview:textView]; + [containerView addSubview:entryImageView]; + + UIImage *sendBtnBackground = [[UIImage imageNamed:@"MessageEntrySendButton.png"] stretchableImageWithLeftCapWidth:13 topCapHeight:0]; + UIImage *selectedSendBtnBackground = [[UIImage imageNamed:@"MessageEntrySendButton.png"] stretchableImageWithLeftCapWidth:13 topCapHeight:0]; + + UIButton *doneBtn = [UIButton buttonWithType:UIButtonTypeCustom]; + doneBtn.frame = CGRectMake(containerView.frame.size.width - 69, 8, 63, 27); + doneBtn.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin; + [doneBtn setTitle:@"Done" forState:UIControlStateNormal]; + + [doneBtn setTitleShadowColor:[UIColor colorWithWhite:0 alpha:0.4] forState:UIControlStateNormal]; + doneBtn.titleLabel.shadowOffset = CGSizeMake (0.0, -1.0); + doneBtn.titleLabel.font = [UIFont boldSystemFontOfSize:18.0f]; + + [doneBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [doneBtn addTarget:self action:@selector(resignTextView) forControlEvents:UIControlEventTouchUpInside]; + [doneBtn setBackgroundImage:sendBtnBackground forState:UIControlStateNormal]; + [doneBtn setBackgroundImage:selectedSendBtnBackground forState:UIControlStateSelected]; + [containerView addSubview:doneBtn]; + containerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin; +} + +-(void)resignTextView +{ + [textView resignFirstResponder]; +} + +//Code from Brett Schumann +-(void) keyboardWillShow:(NSNotification *)note{ + // get keyboard size and loctaion + CGRect keyboardBounds; + [[note.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] getValue: &keyboardBounds]; + NSNumber *duration = [note.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey]; + NSNumber *curve = [note.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey]; + + // Need to translate the bounds to account for rotation. + keyboardBounds = [self.view convertRect:keyboardBounds toView:nil]; + + // get a rect for the textView frame + CGRect containerFrame = containerView.frame; + containerFrame.origin.y = self.view.bounds.size.height - (keyboardBounds.size.height + containerFrame.size.height); + // animations settings + [UIView beginAnimations:nil context:NULL]; + [UIView setAnimationBeginsFromCurrentState:YES]; + [UIView setAnimationDuration:[duration doubleValue]]; + [UIView setAnimationCurve:[curve intValue]]; + + // set views with new info + containerView.frame = containerFrame; + + // commit animations + [UIView commitAnimations]; +} + +-(void) keyboardWillHide:(NSNotification *)note{ + NSNumber *duration = [note.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey]; + NSNumber *curve = [note.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey]; + + // get a rect for the textView frame + CGRect containerFrame = containerView.frame; + containerFrame.origin.y = self.view.bounds.size.height - containerFrame.size.height; + + // animations settings + [UIView beginAnimations:nil context:NULL]; + [UIView setAnimationBeginsFromCurrentState:YES]; + [UIView setAnimationDuration:[duration doubleValue]]; + [UIView setAnimationCurve:[curve intValue]]; + + // set views with new info + containerView.frame = containerFrame; + + // commit animations + [UIView commitAnimations]; +} + +- (void)growingTextView:(HPGrowingTextView *)growingTextView willChangeHeight:(float)height +{ + float diff = (growingTextView.frame.size.height - height); + + CGRect r = containerView.frame; + r.size.height -= diff; + r.origin.y += diff; + containerView.frame = r; +} + +-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation +{ + 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)viewDidUnload { + // Release any retained subviews of the main view. + // e.g. self.myOutlet = nil; +} + + +- (void)dealloc { + [chatTableView release]; + [textView release]; + [containerView release]; + [super dealloc]; +} + +# pragma mark UITableViewDelegate methods + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return 5; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + static NSString *CellIdentifier = @"ChatCell"; + + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; + if (cell == nil) { + cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease]; + } + + // Set up the cell... + NSString *cellValue = @"test"; + cell.textLabel.text = cellValue; + + return cell; +} + +@end diff --git a/Classes/ChatViewController.xib b/Classes/ChatViewController.xib new file mode 100644 index 0000000..909c93e --- /dev/null +++ b/Classes/ChatViewController.xib @@ -0,0 +1,150 @@ + + + + 784 + 10B500 + 732 + 1038.2 + 437.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 62 + + + YES + + + + YES + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + YES + + YES + + + YES + + + + YES + + IBFilesOwner + + + IBFirstResponder + + + + 274 + {320, 460} + + + 3 + MQA + + 2 + + + + + + + + YES + + + view + + + + 3 + + + + + YES + + 0 + + + + + + 1 + + + + + -1 + + + File's Owner + + + -2 + + + + + + + YES + + YES + -1.CustomClassName + -2.CustomClassName + 1.IBEditorWindowLastContentRect + 1.IBPluginDependency + + + YES + ChatViewController + UIResponder + {{556, 412}, {320, 480}} + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + YES + + + YES + + + + + YES + + + YES + + + + 3 + + + + YES + + ChatViewController + UIViewController + + IBProjectSource + ChatViewController.h + + + + + 0 + + com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 + + + YES + + 3 + 3.1 + + diff --git a/Classes/RootViewController.h b/Classes/RootViewController.h index 96d27bb..4125de9 100644 --- a/Classes/RootViewController.h +++ b/Classes/RootViewController.h @@ -9,7 +9,7 @@ #import -@interface RootViewController : UIViewController { +@interface RootViewController : UIViewController { IBOutlet UIWebView *webView; } diff --git a/Classes/RootViewController.m b/Classes/RootViewController.m index 053242c..f647a5e 100644 --- a/Classes/RootViewController.m +++ b/Classes/RootViewController.m @@ -28,7 +28,7 @@ - (void)viewDidLoad { [super viewDidLoad]; - [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://google-developers.appspot.com/maps/documentation/javascript/examples/map-simple"]]]; + [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://google-developers.appspot.com/maps/documentation/javascript/examples/event-closure"]]]; } @@ -60,4 +60,16 @@ } +# pragma mark UIWebViewDelegate methods + +- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { + if (navigationType == UIWebViewNavigationTypeLinkClicked) { + // Flip and open chat view + NSLog(@"UIWebView item clicked"); + } + + return YES; +} + + @end diff --git a/NearMe.xcodeproj/project.pbxproj b/NearMe.xcodeproj/project.pbxproj index ea7c93c..c9a22c2 100755 --- a/NearMe.xcodeproj/project.pbxproj +++ b/NearMe.xcodeproj/project.pbxproj @@ -17,6 +17,18 @@ 288765FD0DF74451002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765FC0DF74451002DB57D /* CoreGraphics.framework */; }; D134D6E51617685C0098794B /* RootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D134D6E31617685C0098794B /* RootViewController.m */; }; D134D6E61617685C0098794B /* RootViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D134D6E41617685C0098794B /* RootViewController.xib */; }; + D134D777161778790098794B /* ChatViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D134D775161778790098794B /* ChatViewController.m */; }; + D134D778161778790098794B /* ChatViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D134D776161778790098794B /* ChatViewController.xib */; }; + D134D7D4161780390098794B /* HPGrowingTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = D134D7D1161780390098794B /* HPGrowingTextView.m */; }; + D134D7D5161780390098794B /* HPTextViewInternal.m in Sources */ = {isa = PBXBuildFile; fileRef = D134D7D3161780390098794B /* HPTextViewInternal.m */; }; + D134D806161781F50098794B /* MessageEntryBackground.png in Resources */ = {isa = PBXBuildFile; fileRef = D134D7FE161781F50098794B /* MessageEntryBackground.png */; }; + D134D807161781F50098794B /* MessageEntryBackground@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D134D7FF161781F50098794B /* MessageEntryBackground@2x.png */; }; + D134D808161781F50098794B /* MessageEntryInputField.png in Resources */ = {isa = PBXBuildFile; fileRef = D134D800161781F50098794B /* MessageEntryInputField.png */; }; + D134D809161781F50098794B /* MessageEntryInputField@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D134D801161781F50098794B /* MessageEntryInputField@2x.png */; }; + D134D80A161781F50098794B /* MessageEntrySendButton.png in Resources */ = {isa = PBXBuildFile; fileRef = D134D802161781F50098794B /* MessageEntrySendButton.png */; }; + D134D80B161781F50098794B /* MessageEntrySendButton@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D134D803161781F50098794B /* MessageEntrySendButton@2x.png */; }; + D134D80C161781F50098794B /* MessageEntrySendButtonPressed.png in Resources */ = {isa = PBXBuildFile; fileRef = D134D804161781F50098794B /* MessageEntrySendButtonPressed.png */; }; + D134D80D161781F50098794B /* MessageEntrySendButtonPressed@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D134D805161781F50098794B /* MessageEntrySendButtonPressed@2x.png */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -36,6 +48,21 @@ D134D6E21617685C0098794B /* RootViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RootViewController.h; path = Classes/RootViewController.h; sourceTree = ""; }; D134D6E31617685C0098794B /* RootViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RootViewController.m; path = Classes/RootViewController.m; sourceTree = ""; }; D134D6E41617685C0098794B /* RootViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = RootViewController.xib; path = Classes/RootViewController.xib; sourceTree = ""; }; + D134D774161778790098794B /* ChatViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ChatViewController.h; path = Classes/ChatViewController.h; sourceTree = ""; }; + D134D775161778790098794B /* ChatViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ChatViewController.m; path = Classes/ChatViewController.m; sourceTree = ""; }; + D134D776161778790098794B /* ChatViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = ChatViewController.xib; path = Classes/ChatViewController.xib; sourceTree = ""; }; + D134D7D0161780390098794B /* HPGrowingTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HPGrowingTextView.h; path = Vendor/HPGrowingTextView.h; sourceTree = ""; }; + D134D7D1161780390098794B /* HPGrowingTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HPGrowingTextView.m; path = Vendor/HPGrowingTextView.m; sourceTree = ""; }; + D134D7D2161780390098794B /* HPTextViewInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HPTextViewInternal.h; path = Vendor/HPTextViewInternal.h; sourceTree = ""; }; + D134D7D3161780390098794B /* HPTextViewInternal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HPTextViewInternal.m; path = Vendor/HPTextViewInternal.m; sourceTree = ""; }; + D134D7FE161781F50098794B /* MessageEntryBackground.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = MessageEntryBackground.png; sourceTree = ""; }; + D134D7FF161781F50098794B /* MessageEntryBackground@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "MessageEntryBackground@2x.png"; sourceTree = ""; }; + D134D800161781F50098794B /* MessageEntryInputField.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = MessageEntryInputField.png; sourceTree = ""; }; + D134D801161781F50098794B /* MessageEntryInputField@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "MessageEntryInputField@2x.png"; sourceTree = ""; }; + D134D802161781F50098794B /* MessageEntrySendButton.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = MessageEntrySendButton.png; sourceTree = ""; }; + D134D803161781F50098794B /* MessageEntrySendButton@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "MessageEntrySendButton@2x.png"; sourceTree = ""; }; + D134D804161781F50098794B /* MessageEntrySendButtonPressed.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = MessageEntrySendButtonPressed.png; sourceTree = ""; }; + D134D805161781F50098794B /* MessageEntrySendButtonPressed@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "MessageEntrySendButtonPressed@2x.png"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -99,6 +126,7 @@ 29B97323FDCFA39411CA2CEA /* Frameworks */, 19C28FACFE9D520D11CA2CBB /* Products */, D134D6E91617687A0098794B /* xib */, + D134D7FD161781F50098794B /* Resources */, ); name = CustomTemplate; sourceTree = ""; @@ -125,8 +153,11 @@ D134D6E8161768700098794B /* Classes */ = { isa = PBXGroup; children = ( + D134D774161778790098794B /* ChatViewController.h */, + D134D775161778790098794B /* ChatViewController.m */, D134D6E21617685C0098794B /* RootViewController.h */, D134D6E31617685C0098794B /* RootViewController.m */, + D134D7D61617803D0098794B /* Vendor */, ); name = Classes; sourceTree = ""; @@ -134,11 +165,38 @@ D134D6E91617687A0098794B /* xib */ = { isa = PBXGroup; children = ( + D134D776161778790098794B /* ChatViewController.xib */, D134D6E41617685C0098794B /* RootViewController.xib */, ); name = xib; sourceTree = ""; }; + D134D7D61617803D0098794B /* Vendor */ = { + isa = PBXGroup; + children = ( + D134D7D0161780390098794B /* HPGrowingTextView.h */, + D134D7D1161780390098794B /* HPGrowingTextView.m */, + D134D7D2161780390098794B /* HPTextViewInternal.h */, + D134D7D3161780390098794B /* HPTextViewInternal.m */, + ); + name = Vendor; + sourceTree = ""; + }; + D134D7FD161781F50098794B /* Resources */ = { + isa = PBXGroup; + children = ( + D134D7FE161781F50098794B /* MessageEntryBackground.png */, + D134D7FF161781F50098794B /* MessageEntryBackground@2x.png */, + D134D800161781F50098794B /* MessageEntryInputField.png */, + D134D801161781F50098794B /* MessageEntryInputField@2x.png */, + D134D802161781F50098794B /* MessageEntrySendButton.png */, + D134D803161781F50098794B /* MessageEntrySendButton@2x.png */, + D134D804161781F50098794B /* MessageEntrySendButtonPressed.png */, + D134D805161781F50098794B /* MessageEntrySendButtonPressed@2x.png */, + ); + path = Resources; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -184,6 +242,15 @@ 2860E329111B887F00E27156 /* MainWindow_iPhone.xib in Resources */, 2860E32F111B888700E27156 /* MainWindow_iPad.xib in Resources */, D134D6E61617685C0098794B /* RootViewController.xib in Resources */, + D134D778161778790098794B /* ChatViewController.xib in Resources */, + D134D806161781F50098794B /* MessageEntryBackground.png in Resources */, + D134D807161781F50098794B /* MessageEntryBackground@2x.png in Resources */, + D134D808161781F50098794B /* MessageEntryInputField.png in Resources */, + D134D809161781F50098794B /* MessageEntryInputField@2x.png in Resources */, + D134D80A161781F50098794B /* MessageEntrySendButton.png in Resources */, + D134D80B161781F50098794B /* MessageEntrySendButton@2x.png in Resources */, + D134D80C161781F50098794B /* MessageEntrySendButtonPressed.png in Resources */, + D134D80D161781F50098794B /* MessageEntrySendButtonPressed@2x.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -198,6 +265,9 @@ 2860E328111B887F00E27156 /* AppDelegate_iPhone.m in Sources */, 2860E32E111B888700E27156 /* AppDelegate_iPad.m in Sources */, D134D6E51617685C0098794B /* RootViewController.m in Sources */, + D134D777161778790098794B /* ChatViewController.m in Sources */, + D134D7D4161780390098794B /* HPGrowingTextView.m in Sources */, + D134D7D5161780390098794B /* HPTextViewInternal.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/README.md b/README.md index 1e6b484..7d07a8d 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ Babblr ====== +ws://poddb.com:9394/ diff --git a/Resources/MessageEntryBackground.png b/Resources/MessageEntryBackground.png new file mode 100644 index 0000000..1db2bce Binary files /dev/null and b/Resources/MessageEntryBackground.png differ diff --git a/Resources/MessageEntryBackground@2x.png b/Resources/MessageEntryBackground@2x.png new file mode 100644 index 0000000..53d805a Binary files /dev/null and b/Resources/MessageEntryBackground@2x.png differ diff --git a/Resources/MessageEntryInputField.png b/Resources/MessageEntryInputField.png new file mode 100644 index 0000000..f784561 Binary files /dev/null and b/Resources/MessageEntryInputField.png differ diff --git a/Resources/MessageEntryInputField@2x.png b/Resources/MessageEntryInputField@2x.png new file mode 100644 index 0000000..6841607 Binary files /dev/null and b/Resources/MessageEntryInputField@2x.png differ diff --git a/Resources/MessageEntrySendButton.png b/Resources/MessageEntrySendButton.png new file mode 100644 index 0000000..1c7d1d8 Binary files /dev/null and b/Resources/MessageEntrySendButton.png differ diff --git a/Resources/MessageEntrySendButton@2x.png b/Resources/MessageEntrySendButton@2x.png new file mode 100644 index 0000000..086083d Binary files /dev/null and b/Resources/MessageEntrySendButton@2x.png differ diff --git a/Resources/MessageEntrySendButtonPressed.png b/Resources/MessageEntrySendButtonPressed.png new file mode 100644 index 0000000..f7397d1 Binary files /dev/null and b/Resources/MessageEntrySendButtonPressed.png differ diff --git a/Resources/MessageEntrySendButtonPressed@2x.png b/Resources/MessageEntrySendButtonPressed@2x.png new file mode 100644 index 0000000..c9a662c Binary files /dev/null and b/Resources/MessageEntrySendButtonPressed@2x.png differ diff --git a/Vendor/HPGrowingTextView.h b/Vendor/HPGrowingTextView.h new file mode 100644 index 0000000..200b3e0 --- /dev/null +++ b/Vendor/HPGrowingTextView.h @@ -0,0 +1,107 @@ +// +// HPTextView.h +// +// Created by Hans Pinckaers on 29-06-10. +// +// MIT License +// +// Copyright (c) 2011 Hans Pinckaers +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +@class HPGrowingTextView; +@class HPTextViewInternal; + +@protocol HPGrowingTextViewDelegate + +@optional +- (BOOL)growingTextViewShouldBeginEditing:(HPGrowingTextView *)growingTextView; +- (BOOL)growingTextViewShouldEndEditing:(HPGrowingTextView *)growingTextView; + +- (void)growingTextViewDidBeginEditing:(HPGrowingTextView *)growingTextView; +- (void)growingTextViewDidEndEditing:(HPGrowingTextView *)growingTextView; + +- (BOOL)growingTextView:(HPGrowingTextView *)growingTextView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text; +- (void)growingTextViewDidChange:(HPGrowingTextView *)growingTextView; + +- (void)growingTextView:(HPGrowingTextView *)growingTextView willChangeHeight:(float)height; +- (void)growingTextView:(HPGrowingTextView *)growingTextView didChangeHeight:(float)height; + +- (void)growingTextViewDidChangeSelection:(HPGrowingTextView *)growingTextView; +- (BOOL)growingTextViewShouldReturn:(HPGrowingTextView *)growingTextView; +@end + +@interface HPGrowingTextView : UIView { + HPTextViewInternal *internalTextView; + + int minHeight; + int maxHeight; + + //class properties + int maxNumberOfLines; + int minNumberOfLines; + + BOOL animateHeightChange; + + //uitextview properties + NSObject *delegate; + NSString *text; + UIFont *font; + UIColor *textColor; + UITextAlignment textAlignment; + NSRange selectedRange; + BOOL editable; + UIDataDetectorTypes dataDetectorTypes; + UIReturnKeyType returnKeyType; + + UIEdgeInsets contentInset; +} + +//real class properties +@property int maxNumberOfLines; +@property int minNumberOfLines; +@property BOOL animateHeightChange; +@property (retain) UITextView *internalTextView; + + +//uitextview properties +@property(assign) NSObject *delegate; +@property(nonatomic,assign) NSString *text; +@property(nonatomic,assign) UIFont *font; +@property(nonatomic,assign) UIColor *textColor; +@property(nonatomic) UITextAlignment textAlignment; // default is UITextAlignmentLeft +@property(nonatomic) NSRange selectedRange; // only ranges of length 0 are supported +@property(nonatomic,getter=isEditable) BOOL editable; +@property(nonatomic) UIDataDetectorTypes dataDetectorTypes __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_3_0); +@property (nonatomic) UIReturnKeyType returnKeyType; +@property (assign) UIEdgeInsets contentInset; +@property(nonatomic) BOOL enablesReturnKeyAutomatically; + +//uitextview methods +//need others? use .internalTextView +- (BOOL)becomeFirstResponder; +- (BOOL)resignFirstResponder; +- (BOOL)isFirstResponder; + +- (BOOL)hasText; +- (void)scrollRangeToVisible:(NSRange)range; + +@end diff --git a/Vendor/HPGrowingTextView.m b/Vendor/HPGrowingTextView.m new file mode 100644 index 0000000..5904a4c --- /dev/null +++ b/Vendor/HPGrowingTextView.m @@ -0,0 +1,550 @@ +// +// HPTextView.m +// +// Created by Hans Pinckaers on 29-06-10. +// +// MIT License +// +// Copyright (c) 2011 Hans Pinckaers +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "HPGrowingTextView.h" +#import "HPTextViewInternal.h" + +@interface HPGrowingTextView(private) +-(void)commonInitialiser; +-(void)resizeTextView:(NSInteger)newSizeH; +-(void)growDidStop; +@end + +@implementation HPGrowingTextView +@synthesize internalTextView; +@synthesize delegate; + +@synthesize font; +@synthesize textColor; +@synthesize textAlignment; +@synthesize selectedRange; +@synthesize editable; +@synthesize dataDetectorTypes; +@synthesize animateHeightChange; +@synthesize returnKeyType; + +// having initwithcoder allows us to use HPGrowingTextView in a Nib. -- aob, 9/2011 +- (id)initWithCoder:(NSCoder *)aDecoder +{ + if ((self = [super initWithCoder:aDecoder])) { + [self commonInitialiser]; + } + return self; +} + +- (id)initWithFrame:(CGRect)frame { + if ((self = [super initWithFrame:frame])) { + [self commonInitialiser]; + } + return self; +} + +-(void)commonInitialiser +{ + // Initialization code + CGRect r = self.frame; + r.origin.y = 0; + r.origin.x = 0; + internalTextView = [[HPTextViewInternal alloc] initWithFrame:r]; + internalTextView.delegate = self; + internalTextView.scrollEnabled = NO; + internalTextView.font = [UIFont fontWithName:@"Helvetica" size:13]; + internalTextView.contentInset = UIEdgeInsetsZero; + internalTextView.showsHorizontalScrollIndicator = NO; + internalTextView.text = @"-"; + [self addSubview:internalTextView]; + + UIView *internal = (UIView*)[[internalTextView subviews] objectAtIndex:0]; + minHeight = internal.frame.size.height; + minNumberOfLines = 1; + + animateHeightChange = YES; + + internalTextView.text = @""; + + [self setMaxNumberOfLines:3]; +} + +-(void)sizeToFit +{ + CGRect r = self.frame; + + // check if the text is available in text view or not, if it is available, no need to set it to minimum lenth, it could vary as per the text length + // fix from Ankit Thakur + if ([self.text length] > 0) { + return; + } else { + r.size.height = minHeight; + self.frame = r; + } +} + +-(void)setFrame:(CGRect)aframe +{ + CGRect r = aframe; + r.origin.y = 0; + r.origin.x = contentInset.left; + r.size.width -= contentInset.left + contentInset.right; + + internalTextView.frame = r; + + [super setFrame:aframe]; +} + +-(void)setContentInset:(UIEdgeInsets)inset +{ + contentInset = inset; + + CGRect r = self.frame; + r.origin.y = inset.top - inset.bottom; + r.origin.x = inset.left; + r.size.width -= inset.left + inset.right; + + internalTextView.frame = r; + + [self setMaxNumberOfLines:maxNumberOfLines]; + [self setMinNumberOfLines:minNumberOfLines]; +} + +-(UIEdgeInsets)contentInset +{ + return contentInset; +} + +-(void)setMaxNumberOfLines:(int)n +{ + // Use internalTextView for height calculations, thanks to Gwynne + NSString *saveText = internalTextView.text, *newText = @"-"; + + internalTextView.delegate = nil; + internalTextView.hidden = YES; + + for (int i = 1; i < n; ++i) + newText = [newText stringByAppendingString:@"\n|W|"]; + + internalTextView.text = newText; + + maxHeight = internalTextView.contentSize.height; + + internalTextView.text = saveText; + internalTextView.hidden = NO; + internalTextView.delegate = self; + + [self sizeToFit]; + + maxNumberOfLines = n; +} + +-(int)maxNumberOfLines +{ + return maxNumberOfLines; +} + +-(void)setMinNumberOfLines:(int)m +{ + // Use internalTextView for height calculations, thanks to Gwynne + NSString *saveText = internalTextView.text, *newText = @"-"; + + internalTextView.delegate = nil; + internalTextView.hidden = YES; + + for (int i = 1; i < m; ++i) + newText = [newText stringByAppendingString:@"\n|W|"]; + + internalTextView.text = newText; + + minHeight = internalTextView.contentSize.height; + + internalTextView.text = saveText; + internalTextView.hidden = NO; + internalTextView.delegate = self; + + [self sizeToFit]; + + minNumberOfLines = m; +} + +-(int)minNumberOfLines +{ + return minNumberOfLines; +} + + +- (void)textViewDidChange:(UITextView *)textView +{ + //size of content, so we can set the frame of self + NSInteger newSizeH = internalTextView.contentSize.height; + if(newSizeH < minHeight || !internalTextView.hasText) newSizeH = minHeight; //not smalles than minHeight + if (internalTextView.frame.size.height > maxHeight) newSizeH = maxHeight; // not taller than maxHeight + + if (internalTextView.frame.size.height != newSizeH) + { + // [fixed] Pasting too much text into the view failed to fire the height change, + // thanks to Gwynne + + if (newSizeH > maxHeight && internalTextView.frame.size.height <= maxHeight) + { + newSizeH = maxHeight; + } + + if (newSizeH <= maxHeight) + { + if(animateHeightChange) { + + if ([UIView resolveClassMethod:@selector(animateWithDuration:animations:)]) { +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000 + [UIView animateWithDuration:0.1f + delay:0 + options:(UIViewAnimationOptionAllowUserInteraction| + UIViewAnimationOptionBeginFromCurrentState) + animations:^(void) { + [self resizeTextView:newSizeH]; + } + completion:^(BOOL finished) { + if ([delegate respondsToSelector:@selector(growingTextView:didChangeHeight:)]) { + [delegate growingTextView:self didChangeHeight:newSizeH]; + } + }]; +#endif + } else { + [UIView beginAnimations:@"" context:nil]; + [UIView setAnimationDuration:0.1f]; + [UIView setAnimationDelegate:self]; + [UIView setAnimationDidStopSelector:@selector(growDidStop)]; + [UIView setAnimationBeginsFromCurrentState:YES]; + [self resizeTextView:newSizeH]; + [UIView commitAnimations]; + } + } else { + [self resizeTextView:newSizeH]; + // [fixed] The growingTextView:didChangeHeight: delegate method was not called at all when not animating height changes. + // thanks to Gwynne + + if ([delegate respondsToSelector:@selector(growingTextView:didChangeHeight:)]) { + [delegate growingTextView:self didChangeHeight:newSizeH]; + } + } + } + + + // if our new height is greater than the maxHeight + // sets not set the height or move things + // around and enable scrolling + if (newSizeH >= maxHeight) + { + if(!internalTextView.scrollEnabled){ + internalTextView.scrollEnabled = YES; + [internalTextView flashScrollIndicators]; + } + + } else { + internalTextView.scrollEnabled = NO; + } + + } + + + if ([delegate respondsToSelector:@selector(growingTextViewDidChange:)]) { + [delegate growingTextViewDidChange:self]; + } + +} + +-(void)resizeTextView:(NSInteger)newSizeH +{ + if ([delegate respondsToSelector:@selector(growingTextView:willChangeHeight:)]) { + [delegate growingTextView:self willChangeHeight:newSizeH]; + } + + CGRect internalTextViewFrame = self.frame; + internalTextViewFrame.size.height = newSizeH; // + padding + self.frame = internalTextViewFrame; + + internalTextViewFrame.origin.y = contentInset.top - contentInset.bottom; + internalTextViewFrame.origin.x = contentInset.left; + internalTextViewFrame.size.width = internalTextView.contentSize.width; + + internalTextView.frame = internalTextViewFrame; +} + +-(void)growDidStop +{ + if ([delegate respondsToSelector:@selector(growingTextView:didChangeHeight:)]) { + [delegate growingTextView:self didChangeHeight:self.frame.size.height]; + } + +} + +-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event +{ + [internalTextView becomeFirstResponder]; +} + +- (BOOL)becomeFirstResponder +{ + [super becomeFirstResponder]; + return [self.internalTextView becomeFirstResponder]; +} + +-(BOOL)resignFirstResponder +{ + [super resignFirstResponder]; + return [internalTextView resignFirstResponder]; +} + +-(BOOL)isFirstResponder +{ + return [self.internalTextView isFirstResponder]; +} + +- (void)dealloc { + [internalTextView release]; + [super dealloc]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark UITextView properties +/////////////////////////////////////////////////////////////////////////////////////////////////// + +-(void)setText:(NSString *)newText +{ + internalTextView.text = newText; + + // include this line to analyze the height of the textview. + // fix from Ankit Thakur + [self performSelector:@selector(textViewDidChange:) withObject:internalTextView]; +} + +-(NSString*) text +{ + return internalTextView.text; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +-(void)setFont:(UIFont *)afont +{ + internalTextView.font= afont; + + [self setMaxNumberOfLines:maxNumberOfLines]; + [self setMinNumberOfLines:minNumberOfLines]; +} + +-(UIFont *)font +{ + return internalTextView.font; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +-(void)setTextColor:(UIColor *)color +{ + internalTextView.textColor = color; +} + +-(UIColor*)textColor{ + return internalTextView.textColor; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +-(void)setBackgroundColor:(UIColor *)backgroundColor +{ + [super setBackgroundColor:backgroundColor]; + internalTextView.backgroundColor = backgroundColor; +} + +-(UIColor*)backgroundColor +{ + return internalTextView.backgroundColor; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +-(void)setTextAlignment:(UITextAlignment)aligment +{ + internalTextView.textAlignment = aligment; +} + +-(UITextAlignment)textAlignment +{ + return internalTextView.textAlignment; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +-(void)setSelectedRange:(NSRange)range +{ + internalTextView.selectedRange = range; +} + +-(NSRange)selectedRange +{ + return internalTextView.selectedRange; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +-(void)setEditable:(BOOL)beditable +{ + internalTextView.editable = beditable; +} + +-(BOOL)isEditable +{ + return internalTextView.editable; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +-(void)setReturnKeyType:(UIReturnKeyType)keyType +{ + internalTextView.returnKeyType = keyType; +} + +-(UIReturnKeyType)returnKeyType +{ + return internalTextView.returnKeyType; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)setEnablesReturnKeyAutomatically:(BOOL)enablesReturnKeyAutomatically +{ + internalTextView.enablesReturnKeyAutomatically = enablesReturnKeyAutomatically; +} + +- (BOOL)enablesReturnKeyAutomatically +{ + return internalTextView.enablesReturnKeyAutomatically; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +-(void)setDataDetectorTypes:(UIDataDetectorTypes)datadetector +{ + internalTextView.dataDetectorTypes = datadetector; +} + +-(UIDataDetectorTypes)dataDetectorTypes +{ + return internalTextView.dataDetectorTypes; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +- (BOOL)hasText{ + return [internalTextView hasText]; +} + +- (void)scrollRangeToVisible:(NSRange)range +{ + [internalTextView scrollRangeToVisible:range]; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +#pragma mark UITextViewDelegate + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (BOOL)textViewShouldBeginEditing:(UITextView *)textView { + if ([delegate respondsToSelector:@selector(growingTextViewShouldBeginEditing:)]) { + return [delegate growingTextViewShouldBeginEditing:self]; + + } else { + return YES; + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (BOOL)textViewShouldEndEditing:(UITextView *)textView { + if ([delegate respondsToSelector:@selector(growingTextViewShouldEndEditing:)]) { + return [delegate growingTextViewShouldEndEditing:self]; + + } else { + return YES; + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (void)textViewDidBeginEditing:(UITextView *)textView { + if ([delegate respondsToSelector:@selector(growingTextViewDidBeginEditing:)]) { + [delegate growingTextViewDidBeginEditing:self]; + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (void)textViewDidEndEditing:(UITextView *)textView { + if ([delegate respondsToSelector:@selector(growingTextViewDidEndEditing:)]) { + [delegate growingTextViewDidEndEditing:self]; + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range + replacementText:(NSString *)atext { + + //weird 1 pixel bug when clicking backspace when textView is empty + if(![textView hasText] && [atext isEqualToString:@""]) return NO; + + //Added by bretdabaker: sometimes we want to handle this ourselves + if ([delegate respondsToSelector:@selector(growingTextView:shouldChangeTextInRange:replacementText:)]) + return [delegate growingTextView:self shouldChangeTextInRange:range replacementText:atext]; + + if ([atext isEqualToString:@"\n"]) { + if ([delegate respondsToSelector:@selector(growingTextViewShouldReturn:)]) { + if (![delegate performSelector:@selector(growingTextViewShouldReturn:) withObject:self]) { + return YES; + } else { + [textView resignFirstResponder]; + return NO; + } + } + } + + return YES; + + +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (void)textViewDidChangeSelection:(UITextView *)textView { + if ([delegate respondsToSelector:@selector(growingTextViewDidChangeSelection:)]) { + [delegate growingTextViewDidChangeSelection:self]; + } +} + + + +@end diff --git a/Vendor/HPTextViewInternal.h b/Vendor/HPTextViewInternal.h new file mode 100644 index 0000000..c44ac63 --- /dev/null +++ b/Vendor/HPTextViewInternal.h @@ -0,0 +1,34 @@ +// +// HPTextViewInternal.h +// +// Created by Hans Pinckaers on 29-06-10. +// +// MIT License +// +// Copyright (c) 2011 Hans Pinckaers +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + + +@interface HPTextViewInternal : UITextView { +} + +@end diff --git a/Vendor/HPTextViewInternal.m b/Vendor/HPTextViewInternal.m new file mode 100644 index 0000000..9b45702 --- /dev/null +++ b/Vendor/HPTextViewInternal.m @@ -0,0 +1,98 @@ +// +// HPTextViewInternal.m +// +// Created by Hans Pinckaers on 29-06-10. +// +// MIT License +// +// Copyright (c) 2011 Hans Pinckaers +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "HPTextViewInternal.h" + + +@implementation HPTextViewInternal + +-(void)setText:(NSString *)text +{ + BOOL originalValue = self.scrollEnabled; + //If one of GrowingTextView's superviews is a scrollView, and self.scrollEnabled == NO, + //setting the text programatically will cause UIKit to search upwards until it finds a scrollView with scrollEnabled==yes + //then scroll it erratically. Setting scrollEnabled temporarily to YES prevents this. + [self setScrollEnabled:YES]; + [super setText:text]; + [self setScrollEnabled:originalValue]; +} + +-(void)setContentOffset:(CGPoint)s +{ + if(self.tracking || self.decelerating){ + //initiated by user... + + UIEdgeInsets insets = self.contentInset; + insets.bottom = 0; + insets.top = 0; + self.contentInset = insets; + + } else { + + float bottomOffset = (self.contentSize.height - self.frame.size.height + self.contentInset.bottom); + if(s.y < bottomOffset && self.scrollEnabled){ + UIEdgeInsets insets = self.contentInset; + insets.bottom = 8; + insets.top = 0; + self.contentInset = insets; + } + } + + [super setContentOffset:s]; +} + +-(void)setContentInset:(UIEdgeInsets)s +{ + UIEdgeInsets insets = s; + + if(s.bottom>8) insets.bottom = 0; + insets.top = 0; + + [super setContentInset:insets]; +} + +-(void)setContentSize:(CGSize)contentSize +{ + // is this an iOS5 bug? Need testing! + if(self.contentSize.height > contentSize.height) + { + UIEdgeInsets insets = self.contentInset; + insets.bottom = 0; + insets.top = 0; + self.contentInset = insets; + } + + [super setContentSize:contentSize]; +} + + +- (void)dealloc { + [super dealloc]; +} + + +@end diff --git a/iPhone/AppDelegate_iPhone.m b/iPhone/AppDelegate_iPhone.m index 566b8cd..31a23e4 100644 --- a/iPhone/AppDelegate_iPhone.m +++ b/iPhone/AppDelegate_iPhone.m @@ -8,6 +8,7 @@ #import "AppDelegate_iPhone.h" #import "RootViewController.h" +#import "ChatViewController.h" @implementation AppDelegate_iPhone @@ -21,7 +22,9 @@ // Override point for customization after application launch. RootViewController *rootVC = [[RootViewController alloc] initWithNibName:@"RootViewController" bundle:nil]; - [window setRootViewController:rootVC]; + ChatViewController *chatVC = [[ChatViewController alloc] init]; +// [window setRootViewController:rootVC]; + [window addSubview:chatVC.view]; [window makeKeyAndVisible]; -- cgit v1.2.3