mirror of
https://github.com/samsonjs/samhuri.net-ios.git
synced 2026-04-18 13:25:51 +00:00
improve visual design and animations, especially for navbar titles
This commit is contained in:
parent
9c5613552c
commit
c3d419f3e9
3 changed files with 230 additions and 196 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 = ^{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue