improve visual design and animations, especially for navbar titles

This commit is contained in:
Sami Samhuri 2015-05-05 00:26:26 -07:00
parent 9c5613552c
commit c3d419f3e9
3 changed files with 230 additions and 196 deletions

View file

@ -6,7 +6,7 @@
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
</dependencies>
<customFonts key="customFonts">
<mutableArray key="FontAwesome.otf">
<mutableArray key="FontAwesome.ttf">
<string>FontAwesome</string>
<string>FontAwesome</string>
</mutableArray>
@ -45,29 +45,6 @@
<rect key="frame" x="0.0" y="0.0" width="600" height="536"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<toolbar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" barStyle="black" translucent="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YUD-Xe-6Cc">
<rect key="frame" x="0.0" y="492" width="600" height="44"/>
<items>
<barButtonItem title="Publish" id="qEb-VA-ueB">
<connections>
<action selector="publishOrUnpublish:" destination="JEX-9P-axG" id="Vxe-Fp-IDn"/>
</connections>
</barButtonItem>
<barButtonItem style="plain" systemItem="flexibleSpace" id="gv8-wH-bFT"/>
<barButtonItem title="Save" id="7iR-uF-xqE">
<connections>
<action selector="save:" destination="JEX-9P-axG" id="gnN-zi-lxN"/>
</connections>
</barButtonItem>
<barButtonItem style="plain" systemItem="flexibleSpace" id="dZ8-jR-S40"/>
<barButtonItem title="Preview" id="uGx-Jy-rOz">
<connections>
<segue destination="ixd-IL-hNy" kind="show" identifier="showPreview" id="eVY-Ks-1b3"/>
</connections>
</barButtonItem>
</items>
<color key="barTintColor" red="0.1333333333" green="0.1333333333" blue="0.1333333333" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</toolbar>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="D5w-s5-7oj" userLabel="Link View">
<rect key="frame" x="0.0" y="0.0" width="600" height="30"/>
<subviews>
@ -79,7 +56,7 @@
</constraints>
<fontDescription key="fontDescription" name="FontAwesome" family="FontAwesome" pointSize="12"/>
<state key="normal" title="8">
<color key="titleColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<color key="titleColor" red="0.85337860840740765" green="0.85337860840740765" blue="0.85337860840740765" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<variation key="default">
@ -114,6 +91,7 @@
</connections>
</button>
</subviews>
<color key="backgroundColor" red="0.66666666669999997" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="centerY" secondItem="ydf-ii-P8M" secondAttribute="centerY" id="0vl-tP-uea"/>
<constraint firstItem="ydf-ii-P8M" firstAttribute="leading" secondItem="UEU-f2-Xco" secondAttribute="trailing" id="FNL-XF-p0M"/>
@ -136,8 +114,24 @@
</mask>
</variation>
</view>
<label opaque="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Using Emacs to Develop Mojo Apps for WebOS or Something Even Longer Than That" textAlignment="center" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HlE-1R-AqU" userLabel="Title Label">
<rect key="frame" x="21" y="38" width="559" height="41"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
<color key="textColor" red="0.96862745100000003" green="0.96862745100000003" blue="0.96862745100000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
<connections>
<outletCollection property="gestureRecognizers" destination="ZZP-5U-wrY" appends="YES" id="nYV-e7-uFl"/>
</connections>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Cwh-4G-e0V" userLabel="Separator View">
<rect key="frame" x="0.0" y="87" width="600" height="1"/>
<color key="backgroundColor" red="0.31372549019607843" green="0.31372549019607843" blue="0.31372549019607843" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="zkb-Pd-Wg0"/>
</constraints>
</view>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" restorationIdentifier="Editor Text View" alwaysBounceVertical="YES" translatesAutoresizingMaskIntoConstraints="NO" id="wrG-1y-ZY3">
<rect key="frame" x="0.0" y="30" width="600" height="462"/>
<rect key="frame" x="0.0" y="88" width="600" height="404"/>
<color key="backgroundColor" red="0.26666666666666666" green="0.26666666666666666" blue="0.26666666666666666" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<string key="text">The latest technology I've been learning is Palm's SDK for webOS,
Mojo. My first impression is that it's a great platform and
@ -175,30 +169,76 @@ started with. There are wrappers around (all?) of the Palm SDK
commands but it needed a bit of work to make it just do what I
wanted with as little input and thought as possible.</string>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" name="MuseoSans-300" family="Museo Sans" pointSize="16"/>
<fontDescription key="fontDescription" name="MuseoSans-300" family="Museo Sans" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
<connections>
<outlet property="delegate" destination="JEX-9P-axG" id="vKD-HY-lGQ"/>
</connections>
</textView>
<toolbar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" barStyle="black" translucent="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YUD-Xe-6Cc">
<rect key="frame" x="0.0" y="492" width="600" height="44"/>
<items>
<barButtonItem title="Publish" id="qEb-VA-ueB">
<connections>
<action selector="publishOrUnpublish:" destination="JEX-9P-axG" id="Vxe-Fp-IDn"/>
</connections>
</barButtonItem>
<barButtonItem style="plain" systemItem="flexibleSpace" id="gv8-wH-bFT"/>
<barButtonItem title="Save" id="7iR-uF-xqE">
<connections>
<action selector="save:" destination="JEX-9P-axG" id="gnN-zi-lxN"/>
</connections>
</barButtonItem>
<barButtonItem style="plain" systemItem="flexibleSpace" id="dZ8-jR-S40"/>
<barButtonItem title="Preview" id="uGx-Jy-rOz">
<connections>
<segue destination="ixd-IL-hNy" kind="show" identifier="showPreview" id="eVY-Ks-1b3"/>
</connections>
</barButtonItem>
</items>
<color key="barTintColor" red="0.1333333333" green="0.1333333333" blue="0.1333333333" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</toolbar>
</subviews>
<color key="backgroundColor" red="0.1333333333" green="0.1333333333" blue="0.1333333333" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="backgroundColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="tintColor" red="0.7953414352" green="0.0" blue="0.013255690590000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="D5w-s5-7oj" firstAttribute="top" secondItem="SYR-Wa-9uf" secondAttribute="bottom" id="0ff-4l-Opw"/>
<constraint firstAttribute="centerX" secondItem="Cwh-4G-e0V" secondAttribute="centerX" id="3Hg-As-HnU"/>
<constraint firstItem="Cwh-4G-e0V" firstAttribute="width" secondItem="svH-Pt-448" secondAttribute="width" id="3dn-X1-5mN"/>
<constraint firstItem="HlE-1R-AqU" firstAttribute="width" relation="lessThanOrEqual" secondItem="svH-Pt-448" secondAttribute="width" constant="-16" id="4Oy-n1-WtG"/>
<constraint firstItem="Cwh-4G-e0V" firstAttribute="top" secondItem="HlE-1R-AqU" secondAttribute="bottom" constant="8" id="8NU-7M-ijy"/>
<constraint firstAttribute="width" secondItem="wrG-1y-ZY3" secondAttribute="width" id="8hl-Ab-ACB"/>
<constraint firstItem="HlE-1R-AqU" firstAttribute="top" secondItem="SYR-Wa-9uf" secondAttribute="bottom" constant="8" id="D1B-pF-bcv"/>
<constraint firstItem="YUD-Xe-6Cc" firstAttribute="bottom" secondItem="GAO-Cl-Wes" secondAttribute="top" id="DLQ-Z3-h8m"/>
<constraint firstItem="wrG-1y-ZY3" firstAttribute="top" secondItem="HlE-1R-AqU" secondAttribute="bottom" constant="8" id="EKu-59-ks3"/>
<constraint firstAttribute="centerX" secondItem="wrG-1y-ZY3" secondAttribute="centerX" id="FEY-jO-Mjl"/>
<constraint firstAttribute="centerX" secondItem="YUD-Xe-6Cc" secondAttribute="centerX" id="JTh-pp-5hr"/>
<constraint firstItem="D5w-s5-7oj" firstAttribute="top" secondItem="HlE-1R-AqU" secondAttribute="bottom" constant="8" id="Zcn-DF-ltb"/>
<constraint firstAttribute="centerX" secondItem="HlE-1R-AqU" secondAttribute="centerX" id="c3k-r8-rud"/>
<constraint firstItem="wrG-1y-ZY3" firstAttribute="top" secondItem="Cwh-4G-e0V" secondAttribute="bottom" id="dSB-Um-tlW"/>
<constraint firstItem="wrG-1y-ZY3" firstAttribute="top" secondItem="D5w-s5-7oj" secondAttribute="bottom" id="dyd-fn-rUM"/>
<constraint firstAttribute="trailing" secondItem="D5w-s5-7oj" secondAttribute="trailing" id="fFI-C6-DCV"/>
<constraint firstItem="YUD-Xe-6Cc" firstAttribute="top" secondItem="wrG-1y-ZY3" secondAttribute="bottom" id="iTL-zi-eKI"/>
<constraint firstItem="D5w-s5-7oj" firstAttribute="top" secondItem="SYR-Wa-9uf" secondAttribute="bottom" id="lio-NE-qVt"/>
<constraint firstAttribute="width" secondItem="YUD-Xe-6Cc" secondAttribute="width" id="n19-6i-zpg"/>
<constraint firstItem="D5w-s5-7oj" firstAttribute="leading" secondItem="svH-Pt-448" secondAttribute="leading" id="t3U-SE-qJc"/>
<constraint firstItem="wrG-1y-ZY3" firstAttribute="top" secondItem="SYR-Wa-9uf" secondAttribute="bottom" constant="30" id="tUU-ig-gJV"/>
<constraint firstItem="HlE-1R-AqU" firstAttribute="top" secondItem="SYR-Wa-9uf" secondAttribute="bottom" constant="38" id="wlt-66-WVR"/>
<constraint firstItem="HlE-1R-AqU" firstAttribute="top" secondItem="D5w-s5-7oj" secondAttribute="bottom" priority="750" constant="8" id="zcA-5F-WC6"/>
</constraints>
<variation key="default">
<mask key="constraints">
<exclude reference="Zcn-DF-ltb"/>
<exclude reference="lio-NE-qVt"/>
<exclude reference="D1B-pF-bcv"/>
<exclude reference="EKu-59-ks3"/>
<exclude reference="dyd-fn-rUM"/>
<exclude reference="tUU-ig-gJV"/>
</mask>
</variation>
</view>
<toolbarItems/>
<navigationItem key="navigationItem" title="Using Emacs to Develop Mojo Apps for WebOS" id="mOI-FS-AaM">
<navigationItem key="navigationItem" title="21st November, 2009" id="mOI-FS-AaM">
<barButtonItem key="backBarButtonItem" title=" " id="KtM-fR-xtg"/>
</navigationItem>
<simulatedStatusBarMetrics key="simulatedStatusBarMetrics" statusBarStyle="lightContent"/>
@ -210,11 +250,17 @@ wanted with as little input and thought as possible.</string>
<outlet property="removeLinkButton" destination="81X-Pe-PFV" id="Rx0-IH-fzp"/>
<outlet property="saveBarButtonItem" destination="7iR-uF-xqE" id="8A5-PY-EuS"/>
<outlet property="textView" destination="wrG-1y-ZY3" id="lvo-lm-t7Z"/>
<outlet property="textViewTopConstraint" destination="tUU-ig-gJV" id="Wzj-Rc-kuM"/>
<outlet property="titleLabel" destination="HlE-1R-AqU" id="B79-B5-tSv"/>
<outlet property="titleLabelTopConstraint" destination="wlt-66-WVR" id="2m4-mP-q2B"/>
<outlet property="toolbar" destination="YUD-Xe-6Cc" id="SIv-cT-WDD"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="FJe-Yq-33r" sceneMemberID="firstResponder"/>
<pongPressGestureRecognizer allowableMovement="10" minimumPressDuration="0.5" id="ZZP-5U-wrY">
<connections>
<action selector="presentChangeTitle:" destination="JEX-9P-axG" id="svR-zn-yTo"/>
</connections>
</pongPressGestureRecognizer>
</objects>
<point key="canvasLocation" x="709" y="129"/>
</scene>
@ -235,7 +281,7 @@ wanted with as little input and thought as possible.</string>
<color key="backgroundColor" red="0.2666666667" green="0.2666666667" blue="0.2666666667" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="textColor" red="0.96862745100000003" green="0.96862745100000003" blue="0.96862745100000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits"/>
<textInputTraits key="textInputTraits" autocapitalizationType="words" returnKeyType="done" enablesReturnKeyAutomatically="YES"/>
<connections>
<outlet property="delegate" destination="iGU-Zs-0by" id="22s-mb-pJM"/>
</connections>

View file

@ -19,11 +19,9 @@
@interface EditorViewController () <UITextViewDelegate, UIPopoverPresentationControllerDelegate>
@property (nonatomic, weak) UIView *titleView;
@property (nonatomic, weak) UILabel *titleLabel;
@property (nonatomic, weak) UILabel *statusLabel;
@property (nonatomic, weak) IBOutlet UILabel *titleLabel;
@property (nonatomic, weak) IBOutlet UITextView *textView;
@property (nonatomic, weak) IBOutlet NSLayoutConstraint *textViewTopConstraint;
@property (nonatomic, weak) IBOutlet NSLayoutConstraint *titleLabelTopConstraint;
@property (nonatomic, weak) IBOutlet UIView *linkView;
@property (nonatomic, weak) IBOutlet UIButton *linkIconButton;
@property (nonatomic, weak) IBOutlet UIButton *linkButton;
@ -39,147 +37,11 @@
@implementation EditorViewController
- (void)setupTitleView {
UIView *titleView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 275, 44)];
titleView.userInteractionEnabled = YES;
UILongPressGestureRecognizer *gestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(presentChangeTitle:)];
[titleView addGestureRecognizer:gestureRecognizer];
self.navigationItem.titleView = titleView;
self.titleView = titleView;
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
titleLabel.font = [UIFont boldSystemFontOfSize:16];
titleLabel.textColor = [UIColor whiteColor];
titleLabel.text = self.navigationItem.title;
[titleLabel sizeToFit];
[titleView addSubview:titleLabel];
[titleView addConstraint:[NSLayoutConstraint constraintWithItem:titleLabel attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationLessThanOrEqual toItem:titleView attribute:NSLayoutAttributeWidth multiplier:1 constant:0]];
[titleView addConstraint:[NSLayoutConstraint constraintWithItem:titleLabel attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:titleView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];
[titleView addConstraint:[NSLayoutConstraint constraintWithItem:titleLabel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:titleView attribute:NSLayoutAttributeCenterY multiplier:1 constant:-8]];
self.titleLabel = titleLabel;
UILabel *subtitleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
subtitleLabel.font = [UIFont systemFontOfSize:11];
subtitleLabel.textColor = [UIColor whiteColor];
[titleView addSubview:subtitleLabel];
self.statusLabel = subtitleLabel;
[self.view setNeedsLayout];
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[UIView animateWithDuration:0.3 animations:^{
CGFloat width = CGRectGetWidth(self.titleView.bounds);
self.statusLabel.center = CGPointMake(width / 2, CGRectGetMaxY(self.titleLabel.frame) + 6 + (CGRectGetHeight(self.statusLabel.bounds) / 2));
}];
}
#pragma mark - Managing the detail item
- (void)configureWithPost:(Post *)post {
if (!(post && [post isEqual:self.post])) {
self.post = post;
self.modifiedPost = post;
[self configureView];
}
}
- (void)updateOnClassInjection {
[self configureView];
}
- (void)configureView {
[self configureTitleView];
[self configureLinkView];
[self configureBodyView];
[self configureToolbar];
}
- (void)configureTitleView {
if (!self.post) {
self.titleLabel.text = nil;
self.statusLabel.text = nil;
return;
}
self.titleLabel.text = self.modifiedPost.title.length ? self.modifiedPost.title : @"Untitled";
NSString *statusText = [self statusText];
if (self.statusLabel && ![self.statusLabel.text isEqualToString:statusText]) {
self.statusLabel.text = statusText;
[UIView animateWithDuration:0.3 animations:^{
[self.statusLabel sizeToFit];
}];
[self.view setNeedsLayout];
}
}
- (NSString *)statusText;
{
return self.modifiedPost.draft ? @"Draft" : self.modifiedPost.date;
}
- (void)configureLinkView {
NSURL *url = self.modifiedPost.url;
if (self.post && (url || [self pasteboardHasLink])) {
NSString *title = url ? url.absoluteString : @"Add Link from Pasteboard";
[self.linkButton setTitle:title forState:UIControlStateNormal];
self.removeLinkButton.hidden = !url;
if (self.textViewTopConstraint.constant <= FLT_EPSILON) {
self.linkView.alpha = 0;
[UIView animateWithDuration:0.3 animations:^{
self.linkView.alpha = 1;
self.textViewTopConstraint.constant = CGRectGetMaxY(self.linkView.frame);
}];
}
}
else if (self.textViewTopConstraint.constant > FLT_EPSILON) {
[UIView animateWithDuration:0.3 animations:^{
self.linkView.alpha = 0;
self.textViewTopConstraint.constant = 0;
}];
}
}
- (void)configureBodyView {
NSString *body = nil;
CGPoint scrollOffset = CGPointZero;
Post *post = self.modifiedPost;
if (post) {
body = post.body;
// TODO: restore scroll offset for this post ... user defaults?
}
self.textView.text = body;
self.textView.contentOffset = scrollOffset;
}
- (void)configureToolbar {
BOOL toolbarEnabled = self.modifiedPost != nil;
[self.toolbar.items enumerateObjectsUsingBlock:^(UIBarButtonItem *item, NSUInteger idx, BOOL *stop) {
item.enabled = toolbarEnabled;
}];
self.publishBarButtonItem.title = self.modifiedPost.draft ? @"Publish" : @"Unpublish";
[self configureSaveButton];
}
- (void)configureSaveButton {
self.saveBarButtonItem.enabled = self.dirty;
self.saveBarButtonItem.title = self.dirty ? @"Save" : nil;
[self.toolbar setItems:self.toolbar.items animated:YES];
}
- (void)awakeFromNib {
[super awakeFromNib];
[self setupTitleView];
- (void)viewDidLoad {
[super viewDidLoad];
[self setupFontAwesomeIcons];
}
- (void)setupFontAwesomeIcons {
[self.linkIconButton setTitle:[NSString fontAwesomeIconStringForEnum:FALink] forState:UIControlStateNormal];
[self.removeLinkButton setTitle:[NSString fontAwesomeIconStringForEnum:FATimesCircle] forState:UIControlStateNormal];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSAssert(self.blogController, @"blogController is required");
@ -219,6 +81,99 @@
}
}
#pragma mark - Managing the detail item
- (void)configureWithPost:(Post *)post {
if (!(post && [post isEqual:self.post])) {
self.post = post;
self.modifiedPost = post;
[self configureView];
}
}
- (void)updateOnClassInjection {
[self configureView];
}
- (void)configureView {
[self configureTitleView];
[self configureLinkView];
[self configureBodyView];
[self configureToolbar];
}
- (void)configureTitleView {
if (!self.post) {
self.title = nil;
self.titleLabel.text = nil;
return;
}
self.title = [self statusText];
self.titleLabel.text = self.modifiedPost.title.length ? self.modifiedPost.title : @"Untitled";
}
- (NSString *)statusText {
return self.modifiedPost.draft ? @"Draft" : self.modifiedPost.date;
}
- (void)configureLinkView {
static const CGFloat TitleLabelTopMargin = 8;
NSURL *url = self.modifiedPost.url;
if (self.post && (url || [self pasteboardHasLink])) {
NSString *title = url ? url.absoluteString : @"Add Link from Pasteboard";
[self.linkButton setTitle:title forState:UIControlStateNormal];
self.removeLinkButton.hidden = !url;
const CGFloat titleLabelTop = TitleLabelTopMargin + CGRectGetMaxY(self.linkView.frame);
if (self.titleLabelTopConstraint.constant <= titleLabelTop) {
self.linkView.alpha = 1;
self.linkButton.alpha = 0;
[UIView animateWithDuration:0.3 animations:^{
self.linkButton.alpha = 1;
self.titleLabelTopConstraint.constant = titleLabelTop;
}];
}
}
else if (self.titleLabelTopConstraint.constant > TitleLabelTopMargin) {
[UIView animateWithDuration:0.3 animations:^{
self.linkView.alpha = 0;
self.titleLabelTopConstraint.constant = TitleLabelTopMargin;
}];
}
}
- (void)configureBodyView {
NSString *body = nil;
CGPoint scrollOffset = CGPointZero;
Post *post = self.modifiedPost;
if (post) {
body = post.body;
// TODO: restore scroll offset for this post ... user defaults?
}
self.textView.text = body;
self.textView.contentOffset = scrollOffset;
}
- (void)configureToolbar {
BOOL toolbarEnabled = self.modifiedPost != nil;
[self.toolbar.items enumerateObjectsUsingBlock:^(UIBarButtonItem *item, NSUInteger idx, BOOL *stop) {
item.enabled = toolbarEnabled;
}];
self.publishBarButtonItem.title = self.modifiedPost.draft ? @"Publish" : @"Unpublish";
[self configureSaveButton];
}
- (void)configureSaveButton {
self.saveBarButtonItem.enabled = self.dirty;
self.saveBarButtonItem.title = self.dirty ? @"Save" : nil;
[self.toolbar setItems:self.toolbar.items animated:YES];
}
- (void)setupFontAwesomeIcons {
[self.linkIconButton setTitle:[NSString fontAwesomeIconStringForEnum:FALink] forState:UIControlStateNormal];
[self.removeLinkButton setTitle:[NSString fontAwesomeIconStringForEnum:FATimesCircle] forState:UIControlStateNormal];
}
#pragma mark - Notification handlers
- (void)applicationWillResignActive:(NSNotification *)note {
@ -235,7 +190,11 @@
- (void)keyboardWillShow:(NSNotification *)note {
if (self.textView.isFirstResponder) {
[self showHideKeyboardButton];
// This notification is called inside an animation block, but we don't want animation here.
// Dispatch to break out of the animation.
dispatch_async(dispatch_get_main_queue(), ^{
[self showHideKeyboardButton];
});
}
}
@ -273,7 +232,7 @@ static NSString *const StateRestorationModifiedPostKey = @"modifiedPost";
- (void)showHideKeyboardButton;
{
UIImage *image = [UIImage imageWithIcon:@"fa-chevron-up" backgroundColor:[UIColor clearColor] iconColor:[UIColor mm_colorFromInteger:0xAA0000] fontSize:20];
UIImage *image = [UIImage imageWithIcon:@"fa-chevron-down" backgroundColor:[UIColor clearColor] iconColor:[UIColor mm_colorFromInteger:0xAA0000] fontSize:20];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(0, 0, image.size.width, image.size.height);
[button setImage:image forState:UIControlStateNormal];
@ -400,7 +359,7 @@ static NSString *const StateRestorationModifiedPostKey = @"modifiedPost";
UIPopoverPresentationController *presentationController = changeTitleViewController.popoverPresentationController;
presentationController.delegate = self;
presentationController.sourceView = self.view;
presentationController.sourceRect = CGRectMake(CGRectGetWidth(self.view.bounds) / 2, 0, 1, 1);
presentationController.sourceRect = CGRectMake(CGRectGetWidth(self.view.bounds) / 2, CGRectGetMaxY(self.titleLabel.frame), 1, 1);
presentationController.permittedArrowDirections = UIPopoverArrowDirectionUp;
__weak __typeof__(changeTitleViewController) weakChangeTitleViewController = changeTitleViewController;
changeTitleViewController.dismissBlock = ^{

View file

@ -7,6 +7,7 @@
//
#import <PromiseKit/Promise.h>
#import <ObjectiveSugar/NSArray+ObjectiveSugar.h>
#import "PostsViewController.h"
#import "EditorViewController.h"
#import "Post.h"
@ -55,24 +56,40 @@ static const NSUInteger SectionPublished = 1;
- (void)setupTitleView {
UIView *titleView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 44)];
titleView.clipsToBounds = YES;
titleView.userInteractionEnabled = YES;
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(requestStatusWithoutCaching)];
recognizer.numberOfTapsRequired = 2;
[titleView addGestureRecognizer:recognizer];
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
titleLabel.font = [UIFont fontWithName:@"MuseoSans-300" size:16];
titleLabel.textColor = [UIColor whiteColor];
titleLabel.text = self.navigationItem.title;
[titleLabel sizeToFit];
[titleView addSubview:titleLabel];
[titleView addConstraint:[NSLayoutConstraint constraintWithItem:titleLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:titleView attribute:NSLayoutAttributeTop multiplier:1 constant:3]];
[titleView addConstraint:[NSLayoutConstraint constraintWithItem:titleLabel attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:titleView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];
self.titleLabel = titleLabel;
UILabel *subtitleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
subtitleLabel.font = [UIFont systemFontOfSize:11];
subtitleLabel.textColor = [UIColor whiteColor];
[subtitleLabel sizeToFit];
[titleView addSubview:subtitleLabel];
[titleView addConstraint:[NSLayoutConstraint constraintWithItem:subtitleLabel attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:titleView attribute:NSLayoutAttributeBottom multiplier:1 constant:-3]];
[titleView addConstraint:[NSLayoutConstraint constraintWithItem:subtitleLabel attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:titleView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];
self.statusLabel = subtitleLabel;
self.navigationItem.titleView = titleView;
[self.view setNeedsLayout];
}
- (void)updateOnClassInjection {
[self.titleLabel.constraints each:^(NSLayoutConstraint *constraint) {
[constraint.secondItem removeConstraint:constraint];
}];
[self.statusLabel.constraints each:^(NSLayoutConstraint *constraint) {
[constraint.secondItem removeConstraint:constraint];
}];
[self setupTitleView];
}
- (void)setupFontAwesomeIcons {
@ -84,17 +101,8 @@ static const NSUInteger SectionPublished = 1;
self.publishButton.customView = button;
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[UIView animateWithDuration:0.3 animations:^{
CGFloat width = CGRectGetWidth(self.titleLabel.superview.bounds);
self.titleLabel.center = CGPointMake(width / 2, 3 + (CGRectGetHeight(self.titleLabel.bounds) / 2));
self.statusLabel.center = CGPointMake(width / 2, CGRectGetMaxY(self.titleLabel.frame) + 3 + (CGRectGetHeight(self.statusLabel.bounds) / 2));
}];
}
- (void)setupBlogStatusTimer {
self.blogStatusTimer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(updateBlogStatus) userInfo:nil repeats:YES];
self.blogStatusTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateBlogStatus) userInfo:nil repeats:YES];
}
- (void)teardownBlogStatusTimer {
@ -102,18 +110,36 @@ static const NSUInteger SectionPublished = 1;
self.blogStatusTimer = nil;
}
- (void)updateStatusLabel:(NSString *)blogStatus {
- (void)updateStatusLabel:(NSString *)blogStatus animated:(BOOL)animated {
if (self.statusLabel && ![self.statusLabel.text isEqualToString:blogStatus]) {
self.statusLabel.text = blogStatus;
[UIView animateWithDuration:0.3 animations:^{
[self.statusLabel sizeToFit];
}];
[self.view setNeedsLayout];
[self.statusLabel sizeToFit];
UIView *titleView = self.statusLabel.superview;
CGFloat x = CGRectGetWidth(titleView.bounds) / 2;
CGFloat y = 50 + CGRectGetHeight(self.statusLabel.frame) / 2;
self.statusLabel.center = CGPointMake(x, y);
self.statusLabel.alpha = 0;
void (^animate)() = ^{
CGRect frame = self.statusLabel.frame;
frame.origin.y = CGRectGetMaxY(self.titleLabel.frame) + 3;
self.statusLabel.frame = frame;
self.statusLabel.alpha = 1;
};
if (animated) {
[UIView animateWithDuration:0.3 animations:animate];
}
else {
animate();
}
}
}
- (void)updateBlogStatus {
[self updateStatusLabel:[NSString stringWithFormat:@"%@ as of %@", self.blogStatusText, [self.blogStatusDate mm_relativeToNow]]];
[self updateStatusLabel:[NSString stringWithFormat:@"%@ as of %@", self.blogStatusText, [self.blogStatusDate mm_relativeToNow]] animated:NO];
}
- (void)updateBlogStatusAnimated:(BOOL)animated {
[self updateStatusLabel:[NSString stringWithFormat:@"%@ as of %@", self.blogStatusText, [self.blogStatusDate mm_relativeToNow]] animated:animated];
}
- (void)viewWillAppear:(BOOL)animated {
@ -124,6 +150,9 @@ static const NSUInteger SectionPublished = 1;
if (!self.postCollections) {
[self requestPostsWithCaching:YES];
}
if (self.tableView.indexPathForSelectedRow) {
[self.tableView deselectRowAtIndexPath:self.tableView.indexPathForSelectedRow animated:YES];
}
}
- (void)viewWillDisappear:(BOOL)animated {
@ -145,7 +174,7 @@ static const NSUInteger SectionPublished = 1;
- (PMKPromise *)requestStatusWithCaching:(BOOL)useCache {
[self teardownBlogStatusTimer];
[self updateStatusLabel:@"Checking status"];
[self updateStatusLabel:@"Checking status" animated:YES];
return [self.blogController requestBlogStatusWithCaching:useCache].then(^(BlogStatus *status) {
self.blogStatusDate = status.date;
if (status.dirty) {
@ -155,10 +184,10 @@ static const NSUInteger SectionPublished = 1;
self.blogStatusText = @"Everything published";
}
[self setupBlogStatusTimer];
[self updateBlogStatus];
[self updateBlogStatusAnimated:YES];
return status;
}).catch(^(NSError *error) {
[self updateStatusLabel:@"Failed to check status"];
[self updateStatusLabel:@"Failed to check status" animated:NO];
return error;
});
}