Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Aviel Gross authored and Aviel Gross committed Apr 29, 2014
1 parent 881e45c commit 21ef693
Show file tree
Hide file tree
Showing 6 changed files with 316 additions and 0 deletions.
26 changes: 26 additions & 0 deletions AGPushNote/AGPushNoteView.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// IAAPushNoteView.h
// TLV Airport
//
// Created by Aviel Gross on 1/29/14.
// Copyright (c) 2014 NGSoft. All rights reserved.
//

#import <UIKit/UIKit.h>
@protocol AGPushNoteViewDelegate <NSObject>
@optional
- (void)pushNoteDidAppear; // Called after the view has been fully transitioned onto the screen. (equel to completion block).
- (void)pushNoteWillDisappear; // Called before the view is hidden, after the message action block.

@end
@interface AGPushNoteView : UIToolbar
+ (void)showWithNotificationMessage:(NSString *)message;
+ (void)showWithNotificationMessage:(NSString *)message completion:(void (^)(void))completion;
+ (void)close;
+ (void)closeWitCompletion:(void (^)(void))completion;
+ (void)awake;

+ (void)setMessageAction:(void (^)(NSString *message))action;

@property (nonatomic, weak) id<AGPushNoteViewDelegate> pushNoteDelegate;
@end
209 changes: 209 additions & 0 deletions AGPushNote/AGPushNoteView.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
//
// IAAPushNoteView.m
// TLV Airport
//
// Created by Aviel Gross on 1/29/14.
// Copyright (c) 2014 NGSoft. All rights reserved.
//

#import "AGPushNoteView.h"

#define APP [UIApplication sharedApplication].delegate
#define isIOS7 (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1)
#define PUSH_VIEW [AGPushNoteView sharedPushView]

#define CLOSE_PUSH_SEC 5
#define SHOW_ANIM_DUR 0.5
#define HIDE_ANIM_DUR 0.35

@interface AGPushNoteView()
@property (weak, nonatomic) IBOutlet UILabel *messageLabel;
@property (weak, nonatomic) IBOutlet UIView *containerView;

@property (strong, nonatomic) NSTimer *closeTimer;
@property (strong, nonatomic) NSString *currentMessage;
@property (strong, nonatomic) NSMutableArray *pendingPushArr;

@property (strong, nonatomic) void (^messageTapActionBlock)(NSString *message);
@end


@implementation AGPushNoteView

//Singleton instance
static AGPushNoteView *_sharedPushView;

+ (instancetype)sharedPushView
{
@synchronized([self class])
{
if (!_sharedPushView){
NSArray *nibArr = [[NSBundle mainBundle] loadNibNamed: @"AGPushNoteView" owner:self options:nil];
for (id currentObject in nibArr)
{
if ([currentObject isKindOfClass:[AGPushNoteView class]])
{
_sharedPushView = (AGPushNoteView *)currentObject;
break;
}
}
[_sharedPushView setUpUI];
}
return _sharedPushView;
}
// to avoid compiler warning
return nil;
}

#pragma mark - Lifecycle (of sort)
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
CGRect f = self.frame;
CGFloat width = [UIApplication sharedApplication].keyWindow.bounds.size.width;
self.frame = CGRectMake(f.origin.x, f.origin.y, width, f.size.height);
}
return self;
}

- (void)setUpUI {
CGRect f = self.frame;
CGFloat width = [UIApplication sharedApplication].keyWindow.bounds.size.width;
CGFloat height = isIOS7? 54: f.size.height;
self.frame = CGRectMake(f.origin.x, -height, width, height);

CGRect cvF = self.containerView.frame;
self.containerView.frame = CGRectMake(cvF.origin.x, cvF.origin.y, self.frame.size.width, cvF.size.height);

//OS Specific:
if (isIOS7) {
self.barTintColor = nil;
self.translucent = YES;
self.barStyle = UIBarStyleBlack;
} else {
[self setTintColor:[UIColor colorWithRed:5 green:31 blue:75 alpha:1]];
[self.messageLabel setTextAlignment:NSTextAlignmentCenter];
self.messageLabel.shadowColor = [UIColor blackColor];
}

self.layer.zPosition = MAXFLOAT;
self.backgroundColor = [UIColor clearColor];
self.multipleTouchEnabled = NO;
self.exclusiveTouch = YES;

UITapGestureRecognizer *msgTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(messageTapAction)];
self.messageLabel.userInteractionEnabled = YES;
[self.messageLabel addGestureRecognizer:msgTap];

//:::[For debugging]:::
// self.containerView.backgroundColor = [UIColor yellowColor];
// self.closeButton.backgroundColor = [UIColor redColor];
// self.messageLabel.backgroundColor = [UIColor greenColor];

[APP.window addSubview:PUSH_VIEW];
}

+ (void)awake {
if (PUSH_VIEW.frame.origin.y == 0) {
[APP.window addSubview:PUSH_VIEW];
}
}

+ (void)showWithNotificationMessage:(NSString *)message {
[AGPushNoteView showWithNotificationMessage:message completion:^{
//Nothing.
}];
}

+ (void)showWithNotificationMessage:(NSString *)message completion:(void (^)(void))completion {

PUSH_VIEW.currentMessage = message;

if (message) {
[PUSH_VIEW.pendingPushArr addObject:message];

PUSH_VIEW.messageLabel.text = message;
APP.window.windowLevel = UIWindowLevelStatusBar;

CGRect f = PUSH_VIEW.frame;
PUSH_VIEW.frame = CGRectMake(f.origin.x, -f.size.height, f.size.width, f.size.height);
[APP.window addSubview:PUSH_VIEW];

//Show
[UIView animateWithDuration:SHOW_ANIM_DUR delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
CGRect f = PUSH_VIEW.frame;
PUSH_VIEW.frame = CGRectMake(f.origin.x, 0, f.size.width, f.size.height);
} completion:^(BOOL finished) {
completion();
if ([PUSH_VIEW.pushNoteDelegate respondsToSelector:@selector(pushNoteDidAppear)]) {
[PUSH_VIEW.pushNoteDelegate pushNoteDidAppear];
}
}];

//Start timer (Currently not used to make sure user see & read the push...)
// PUSH_VIEW.closeTimer = [NSTimer scheduledTimerWithTimeInterval:CLOSE_PUSH_SEC target:[IAAPushNoteView class] selector:@selector(close) userInfo:nil repeats:NO];
}
}
+ (void)closeWitCompletion:(void (^)(void))completion {
if ([PUSH_VIEW.pushNoteDelegate respondsToSelector:@selector(pushNoteWillDisappear)]) {
[PUSH_VIEW.pushNoteDelegate pushNoteWillDisappear];
}

[PUSH_VIEW.closeTimer invalidate];

[UIView animateWithDuration:HIDE_ANIM_DUR delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
CGRect f = PUSH_VIEW.frame;
PUSH_VIEW.frame = CGRectMake(f.origin.x, -f.size.height, f.size.width, f.size.height);
} completion:^(BOOL finished) {
[PUSH_VIEW handlePendingPushJumpWitCompletion:completion];
}];
}

+ (void)close {
[AGPushNoteView closeWitCompletion:^{
//Nothing.
}];
}

#pragma mark - Pending push managment
- (void)handlePendingPushJumpWitCompletion:(void (^)(void))completion {
id lastObj = [self.pendingPushArr lastObject]; //Get myself
if (lastObj) {
[self.pendingPushArr removeObject:lastObj]; //Remove me from arr
NSString *messagePendingPush = [self.pendingPushArr lastObject]; //Maybe get pending push
if (messagePendingPush) { //If got something - remove from arr, - than show it.
[self.pendingPushArr removeObject:messagePendingPush];
[AGPushNoteView showWithNotificationMessage:messagePendingPush completion:completion];
} else {
APP.window.windowLevel = UIWindowLevelNormal;
}
}
}

- (NSMutableArray *)pendingPushArr {
if (!_pendingPushArr) {
_pendingPushArr = [[NSMutableArray alloc] init];
}
return _pendingPushArr;
}

#pragma mark - Actions
+ (void)setMessageAction:(void (^)(NSString *message))action {
PUSH_VIEW.messageTapActionBlock = action;
}

- (void)messageTapAction {
if (self.messageTapActionBlock) {
self.messageTapActionBlock(self.currentMessage);
[AGPushNoteView close];
}
}

- (IBAction)closeActionItem:(UIBarButtonItem *)sender {
[AGPushNoteView close];
}


@end
46 changes: 46 additions & 0 deletions AGPushNote/AGPushNoteView.xib
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="5056" systemVersion="13C1021" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment defaultVersion="1536" identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3733"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<toolbar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" barStyle="black" id="dXp-SS-CuN" customClass="AGPushNoteView">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<items>
<barButtonItem style="done" systemItem="stop" id="pRY-8K-Lxt">
<connections>
<action selector="closeActionItem:" destination="dXp-SS-CuN" id="ToV-av-Emk"/>
</connections>
</barButtonItem>
<barButtonItem style="plain" id="hSw-lx-Uca">
<view key="customView" alpha="0.5" contentMode="scaleToFill" id="E4g-eI-zJ9">
<rect key="frame" x="40" y="0.0" width="270" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="message" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="270" translatesAutoresizingMaskIntoConstraints="NO" id="SuY-fE-zer">
<rect key="frame" x="0.0" y="0.0" width="270" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<color key="tintColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</barButtonItem>
</items>
<color key="barTintColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<connections>
<outlet property="containerView" destination="E4g-eI-zJ9" id="UYa-0B-O43"/>
<outlet property="messageLabel" destination="SuY-fE-zer" id="R8k-sE-qWe"/>
</connections>
</toolbar>
</objects>
</document>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http:https://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges</key>
<true/>
<key>SnapshotAutomaticallyBeforeSignificantChanges</key>
<true/>
</dict>
</plist>
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2014 avielg

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.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
AGPushNote
==========

Custom view for easily displaying in-app push notification that feels like default iOS banners.

0 comments on commit 21ef693

Please sign in to comment.