-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathWAPageViewController.m
286 lines (222 loc) · 10.3 KB
/
WAPageViewController.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
//
// WAPageViewController.m
// Weather
//
// Created by Mitchell Cooper on 12/19/13.
// Copyright (c) 2013-14 Mitchell Cooper. All rights reserved.
//
#import "WALocation.h"
#import "WALocationManager.h"
#import "WANavigationController.h"
#import "WAPageViewController.h"
#import "WAWeatherVC.h"
#import "WAConditionDetailTVC.h"
#import "WADailyForecastTVC.h"
#import "WAHourlyForecastTVC.h"
#import "UINavigationController+Fade.h"
#import "UIImage+WhiteImage.h"
#import "WAMenu/WAMenuItem.h"
@implementation WAPageViewController
#pragma mark - Page view controller
- (instancetype)initWithTransitionStyle:(UIPageViewControllerTransitionStyle)style navigationOrientation:(UIPageViewControllerNavigationOrientation)navigationOrientation options:(NSDictionary *)options {
self = [super initWithTransitionStyle:style navigationOrientation:navigationOrientation options:options];
// this is a looping reference - I am aware.
// however, this object will never be destroyed from start to exit of the application,
// so the hanging refcount does not actually matter at all.
if (self) self.delegate = self;
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// create the menu.
menu = [[WAMenu alloc] initWithFrame:self.view.window.bounds];
menu.delegate = self;
// many different shades of blue.
UIColor *c_0 = RGBA( 0., 70., 200., 1);
UIColor *c_1 = RGBA( 43., 101., 236., 1);
UIColor *c_2 = RGBA( 21., 137., 255., 1);
UIColor *c_3 = RGBA( 56., 172., 236., 1);
UIColor *c_4 = RGBA(130., 202., 255., 1);
// add the menu items.
UIFont *font = [UIFont systemFontOfSize:25];
NSArray *items = @[
@[@"Location list", @"list", c_0],
@[@"Current overview", @"", c_1],
@[@"Extensive details", @"details", c_2],
@[@"Hourly forecast", @"hourly", c_3],
@[@"Daily forecast", @"daily", c_4]
];
for (NSArray *item in items) {
UIImage *icon = [UIImage imageNamed:FMT(@"icons/menu/%@", item[1])];
if (!icon) icon = [UIImage imageNamed:@"icons/30/clear"];
[menu addItem:item[0] icon:icon color:item[2] font:font];
}
// this fixes the navigation bar inset issue.
// however, it causes the page view controller to ignore the navigation bar completely
// (so its frame goes behind the navigation bar as well.)
self.automaticallyAdjustsScrollViewInsets = NO;
self.view.backgroundColor = [UIColor clearColor];
self.view.multipleTouchEnabled = NO;
// custom title view with gesture recognizer for menu.
self.navigationItem.titleView = [self menuLabelWithTitle:@"Overview"];
// refresh button.
refreshButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(refreshButtonTapped)];
self.navigationItem.rightBarButtonItem = refreshButton;
// remove the text on the back button.
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];
// scroll view delegate.
[self.view.subviews[0] setDelegate:self];
// from background.
background = [[UIImageView alloc] initWithFrame:self.view.bounds];
background.backgroundColor = [UIColor clearColor];
[self.view addSubview:background];
[self.view sendSubviewToBack:background];
// to background.
backBackground = [[UIImageView alloc] initWithFrame:self.view.bounds];
backBackground.backgroundColor = [UIColor clearColor];
[self.view addSubview:backBackground];
[self.view sendSubviewToBack:backBackground];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
#pragma mark - Page view controller delegate
- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers {
WAWeatherVC *toVC = pendingViewControllers[0];
NSUInteger i = goingDown ? toVC.location.index - 1 : toVC.location.index + 1;
// set the forebackground to the location we were on already.
WALocation *locationBefore = locationManager.locations[i];
background.image = locationBefore.background;
background.frame = self.view.bounds;
// set the backbackground to that of the upcoming location.
backBackground.image = toVC.location.background;
backBackground.frame = self.view.bounds;
NSLog(@"Transitioning to %@", toVC.location.city);
}
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed {
WAWeatherVC *weatherVC = self.viewControllers[0];
// update the current location.
NSLog(@"Setting current city from %@ to %@", self.location.city, weatherVC.location.city);
self.location = weatherVC.location;
// update the navigation bar and background only if the user lets go.
if (completed) [self updateNavigationBar]; // fixes it.
}
#pragma mark - Update information
// set the current weather view controller, updating location and navigation bar.
- (void)setViewController:(WAWeatherVC *)weatherVC {
[appDelegate.pageViewController setViewControllers:@[weatherVC] direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
self.location = weatherVC.location;
[self updateNavigationBar];
}
// update the information and buttons on the navigation bar.
- (void)updateNavigationBar {
// loading and refresh button is visible.
if (self.location.loading && self.navigationItem.rightBarButtonItem == refreshButton) {
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
[indicator startAnimating];
UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView:indicator];
[self.navigationItem setRightBarButtonItem:item animated:YES];
}
// not loading and refresh button is not visible.
else if (!self.location.loading && self.navigationItem.rightBarButtonItem != refreshButton)
[self.navigationItem setRightBarButtonItem:refreshButton animated:YES];
// update the background while we're at it.
[self updateBackground];
}
// update the background image.
- (void)updateBackground {
if (background.image != self.location.background)
background.image = self.location.background;
background.frame = self.view.bounds;
}
#pragma mark - Interface actions
// update conditions.
- (void)refreshButtonTapped {
[self.location fetchCurrentConditions];
// if the hourly exists, reload that too for the preview.
if (self.location.hourlyForecastResponse)
[self.location fetchHourlyForecast:NO];
[self.location commitRequest];
}
// display the menu.
- (void)titleTapped {
WAMenuItem *item = menu.menuItems[1];
item.name.text = FMT(@"%@ overview", self.location.city);
UIImageView *iconView = (UIImageView *)[item viewWithTag:10];
iconView.image = [UIImage imageNamed:FMT(@"icons/30/%@", self.location.conditionsImageName)];
iconView.image = [iconView.image whiteImage];
[menu showMenu];
}
#pragma mark - Menu
- (void)menuItemSelected:(NSString *)action {
WANavigationController *navigationController = appDelegate.navigationController;
UIViewController *vc;
// decide which item was selected.
if ([action isEqualToString:@"Location list"]) {
[navigationController popToRootViewControllerAnimated:YES];
return;
}
else if ([action rangeOfString:@"overview"].location != NSNotFound) {
vc = self;
}
else if ([action isEqualToString:@"Extensive details"]) {
if (!self.location.detailVC)
self.location.detailVC = [[WAConditionDetailTVC alloc] initWithLocation:self.location];
vc = self.location.detailVC;
}
else if ([action isEqualToString:@"Hourly forecast"]) {
if (!self.location.hourlyVC)
self.location.hourlyVC = [[WAHourlyForecastTVC alloc] initWithLocation:self.location];
vc = self.location.hourlyVC;
}
else if ([action isEqualToString:@"Daily forecast"]) {
if (!self.location.dailyVC)
self.location.dailyVC = [[WADailyForecastTVC alloc] initWithLocation:self.location];
vc = self.location.dailyVC;
}
else return;
// we're already on this view controller.
if (vc == navigationController.topViewController) return;
// for the overview, just pop back to the page view controller (self).
if (vc == self) {
[navigationController popToViewController:self animated:YES];
return;
}
// then move on to the selection.
// if the current top vc is the overview, push to it.
// if it's something else, use the fade transition to avoid confusion.
if (navigationController.topViewController == self) {
[navigationController pushViewController:vc animated:YES];
}
else {
[navigationController popViewControllerAnimated:NO];
[navigationController pushFadeViewController:vc];
}
}
// create a UILabel with a gesture recognizer to show the menu.
// this is used across the different weather data view controllers.
- (UILabel *)menuLabelWithTitle:(NSString *)title {
// create a label of the appropriate dimensions.
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 40)];
titleLabel.userInteractionEnabled = YES;
titleLabel.textAlignment = NSTextAlignmentCenter;
titleLabel.textColor = [UIColor whiteColor];
titleLabel.font = [UIFont boldSystemFontOfSize:17];
titleLabel.text = title;
// add gesture recognizer.
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(titleTapped)];
[titleLabel addGestureRecognizer:tap];
return titleLabel;
}
#pragma mark - Scroll view delegate
// gradually fade the background with scrolling.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat x = scrollView.contentOffset.y / (self.view.bounds.size.height / 100.);
// up or down?
if (x > 100.) goingDown = YES;
else goingDown = NO;
// going down, so subtract from 200.
if (x > 100.) x = 200. - x;
background.alpha = x / 100.;
}
@end