OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2015 The WebRTC Project Authors. All rights reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #import "ARDMainView.h" | |
12 | |
13 #import "UIImage+ARDUtilities.h" | |
14 | |
15 // TODO(tkchin): retrieve status bar height dynamically. | |
16 static CGFloat const kStatusBarHeight = 20; | |
17 | |
18 static CGFloat const kRoomTextButtonSize = 40; | |
19 static CGFloat const kRoomTextFieldHeight = 40; | |
20 static CGFloat const kRoomTextFieldMargin = 8; | |
21 static CGFloat const kCallControlMargin = 8; | |
22 | |
23 // Helper view that contains a text field and a clear button. | |
24 @interface ARDRoomTextField : UIView <UITextFieldDelegate> | |
25 @property(nonatomic, readonly) NSString *roomText; | |
26 @end | |
27 | |
28 @implementation ARDRoomTextField { | |
29 UITextField *_roomText; | |
30 UIButton *_clearButton; | |
31 } | |
32 | |
33 - (instancetype)initWithFrame:(CGRect)frame { | |
34 if (self = [super initWithFrame:frame]) { | |
35 _roomText = [[UITextField alloc] initWithFrame:CGRectZero]; | |
36 _roomText.borderStyle = UITextBorderStyleNone; | |
37 _roomText.font = [UIFont fontWithName:@"Roboto" size:12]; | |
38 _roomText.placeholder = @"Room name"; | |
39 _roomText.autocorrectionType = UITextAutocorrectionTypeNo; | |
40 _roomText.autocapitalizationType = UITextAutocapitalizationTypeNone; | |
41 _roomText.delegate = self; | |
42 [_roomText addTarget:self | |
43 action:@selector(textFieldDidChange:) | |
44 forControlEvents:UIControlEventEditingChanged]; | |
45 [self addSubview:_roomText]; | |
46 | |
47 _clearButton = [UIButton buttonWithType:UIButtonTypeCustom]; | |
48 UIImage *image = [UIImage imageForName:@"ic_clear_black_24dp.png" | |
49 color:[UIColor colorWithWhite:0 alpha:.4]]; | |
50 | |
51 [_clearButton setImage:image forState:UIControlStateNormal]; | |
52 [_clearButton addTarget:self | |
53 action:@selector(onClear:) | |
54 forControlEvents:UIControlEventTouchUpInside]; | |
55 _clearButton.hidden = YES; | |
56 [self addSubview:_clearButton]; | |
57 | |
58 // Give rounded corners and a light gray border. | |
59 self.layer.borderWidth = 1; | |
60 self.layer.borderColor = [[UIColor lightGrayColor] CGColor]; | |
61 self.layer.cornerRadius = 2; | |
62 } | |
63 return self; | |
64 } | |
65 | |
66 - (void)layoutSubviews { | |
67 CGRect bounds = self.bounds; | |
68 _clearButton.frame = CGRectMake(CGRectGetMaxX(bounds) - kRoomTextButtonSize, | |
69 CGRectGetMinY(bounds), | |
70 kRoomTextButtonSize, | |
71 kRoomTextButtonSize); | |
72 _roomText.frame = CGRectMake( | |
73 CGRectGetMinX(bounds) + kRoomTextFieldMargin, | |
74 CGRectGetMinY(bounds), | |
75 CGRectGetMinX(_clearButton.frame) - CGRectGetMinX(bounds) - | |
76 kRoomTextFieldMargin, | |
77 kRoomTextFieldHeight); | |
78 } | |
79 | |
80 - (CGSize)sizeThatFits:(CGSize)size { | |
81 size.height = kRoomTextFieldHeight; | |
82 return size; | |
83 } | |
84 | |
85 - (NSString *)roomText { | |
86 return _roomText.text; | |
87 } | |
88 | |
89 #pragma mark - UITextFieldDelegate | |
90 | |
91 - (BOOL)textFieldShouldReturn:(UITextField *)textField { | |
92 // There is no other control that can take focus, so manually resign focus | |
93 // when return (Join) is pressed to trigger |textFieldDidEndEditing|. | |
94 [textField resignFirstResponder]; | |
95 return YES; | |
96 } | |
97 | |
98 #pragma mark - Private | |
99 | |
100 - (void)textFieldDidChange:(id)sender { | |
101 [self updateClearButton]; | |
102 } | |
103 | |
104 - (void)onClear:(id)sender { | |
105 _roomText.text = @""; | |
106 [self updateClearButton]; | |
107 [_roomText resignFirstResponder]; | |
108 } | |
109 | |
110 - (void)updateClearButton { | |
111 _clearButton.hidden = _roomText.text.length == 0; | |
112 } | |
113 | |
114 @end | |
115 | |
116 @implementation ARDMainView { | |
117 UILabel *_appLabel; | |
118 ARDRoomTextField *_roomText; | |
119 UILabel *_callOptionsLabel; | |
120 UISwitch *_audioOnlySwitch; | |
121 UILabel *_audioOnlyLabel; | |
122 UISwitch *_aecdumpSwitch; | |
123 UILabel *_aecdumpLabel; | |
124 UISwitch *_levelControlSwitch; | |
125 UILabel *_levelControlLabel; | |
126 UISwitch *_loopbackSwitch; | |
127 UILabel *_loopbackLabel; | |
128 UISwitch *_useManualAudioSwitch; | |
129 UILabel *_useManualAudioLabel; | |
130 UIButton *_startCallButton; | |
131 UIButton *_audioLoopButton; | |
132 } | |
133 | |
134 @synthesize delegate = _delegate; | |
135 @synthesize isAudioLoopPlaying = _isAudioLoopPlaying; | |
136 | |
137 - (instancetype)initWithFrame:(CGRect)frame { | |
138 if (self = [super initWithFrame:frame]) { | |
139 _appLabel = [[UILabel alloc] initWithFrame:CGRectZero]; | |
140 _appLabel.text = @"AppRTCMobile"; | |
141 _appLabel.font = [UIFont fontWithName:@"Roboto" size:34]; | |
142 _appLabel.textColor = [UIColor colorWithWhite:0 alpha:.2]; | |
143 [_appLabel sizeToFit]; | |
144 [self addSubview:_appLabel]; | |
145 | |
146 _roomText = [[ARDRoomTextField alloc] initWithFrame:CGRectZero]; | |
147 [self addSubview:_roomText]; | |
148 | |
149 UIFont *controlFont = [UIFont fontWithName:@"Roboto" size:20]; | |
150 UIColor *controlFontColor = [UIColor colorWithWhite:0 alpha:.6]; | |
151 | |
152 _callOptionsLabel = [[UILabel alloc] initWithFrame:CGRectZero]; | |
153 _callOptionsLabel.text = @"Call Options"; | |
154 _callOptionsLabel.font = controlFont; | |
155 _callOptionsLabel.textColor = controlFontColor; | |
156 [_callOptionsLabel sizeToFit]; | |
157 [self addSubview:_callOptionsLabel]; | |
158 | |
159 _audioOnlySwitch = [[UISwitch alloc] initWithFrame:CGRectZero]; | |
160 [_audioOnlySwitch sizeToFit]; | |
161 [self addSubview:_audioOnlySwitch]; | |
162 | |
163 _audioOnlyLabel = [[UILabel alloc] initWithFrame:CGRectZero]; | |
164 _audioOnlyLabel.text = @"Audio only"; | |
165 _audioOnlyLabel.font = controlFont; | |
166 _audioOnlyLabel.textColor = controlFontColor; | |
167 [_audioOnlyLabel sizeToFit]; | |
168 [self addSubview:_audioOnlyLabel]; | |
169 | |
170 _loopbackSwitch = [[UISwitch alloc] initWithFrame:CGRectZero]; | |
171 [_loopbackSwitch sizeToFit]; | |
172 [self addSubview:_loopbackSwitch]; | |
173 | |
174 _loopbackLabel = [[UILabel alloc] initWithFrame:CGRectZero]; | |
175 _loopbackLabel.text = @"Loopback mode"; | |
176 _loopbackLabel.font = controlFont; | |
177 _loopbackLabel.textColor = controlFontColor; | |
178 [_loopbackLabel sizeToFit]; | |
179 [self addSubview:_loopbackLabel]; | |
180 | |
181 _aecdumpSwitch = [[UISwitch alloc] initWithFrame:CGRectZero]; | |
182 [_aecdumpSwitch sizeToFit]; | |
183 [self addSubview:_aecdumpSwitch]; | |
184 | |
185 _aecdumpLabel = [[UILabel alloc] initWithFrame:CGRectZero]; | |
186 _aecdumpLabel.text = @"Create AecDump"; | |
187 _aecdumpLabel.font = controlFont; | |
188 _aecdumpLabel.textColor = controlFontColor; | |
189 [_aecdumpLabel sizeToFit]; | |
190 [self addSubview:_aecdumpLabel]; | |
191 | |
192 _levelControlSwitch = [[UISwitch alloc] initWithFrame:CGRectZero]; | |
193 [_levelControlSwitch sizeToFit]; | |
194 [self addSubview:_levelControlSwitch]; | |
195 | |
196 _levelControlLabel = [[UILabel alloc] initWithFrame:CGRectZero]; | |
197 _levelControlLabel.text = @"Use level controller"; | |
198 _levelControlLabel.font = controlFont; | |
199 _levelControlLabel.textColor = controlFontColor; | |
200 [_levelControlLabel sizeToFit]; | |
201 [self addSubview:_levelControlLabel]; | |
202 | |
203 _useManualAudioSwitch = [[UISwitch alloc] initWithFrame:CGRectZero]; | |
204 [_useManualAudioSwitch sizeToFit]; | |
205 _useManualAudioSwitch.on = YES; | |
206 [self addSubview:_useManualAudioSwitch]; | |
207 | |
208 _useManualAudioLabel = [[UILabel alloc] initWithFrame:CGRectZero]; | |
209 _useManualAudioLabel.text = @"Use manual audio config"; | |
210 _useManualAudioLabel.font = controlFont; | |
211 _useManualAudioLabel.textColor = controlFontColor; | |
212 [_useManualAudioLabel sizeToFit]; | |
213 [self addSubview:_useManualAudioLabel]; | |
214 | |
215 _startCallButton = [UIButton buttonWithType:UIButtonTypeSystem]; | |
216 _startCallButton.backgroundColor = [UIColor blueColor]; | |
217 _startCallButton.layer.cornerRadius = 10; | |
218 _startCallButton.clipsToBounds = YES; | |
219 _startCallButton.contentEdgeInsets = UIEdgeInsetsMake(5, 10, 5, 10); | |
220 [_startCallButton setTitle:@"Start call" | |
221 forState:UIControlStateNormal]; | |
222 _startCallButton.titleLabel.font = controlFont; | |
223 [_startCallButton setTitleColor:[UIColor whiteColor] | |
224 forState:UIControlStateNormal]; | |
225 [_startCallButton setTitleColor:[UIColor lightGrayColor] | |
226 forState:UIControlStateSelected]; | |
227 [_startCallButton sizeToFit]; | |
228 [_startCallButton addTarget:self | |
229 action:@selector(onStartCall:) | |
230 forControlEvents:UIControlEventTouchUpInside]; | |
231 [self addSubview:_startCallButton]; | |
232 | |
233 // Used to test what happens to sounds when calls are in progress. | |
234 _audioLoopButton = [UIButton buttonWithType:UIButtonTypeSystem]; | |
235 _audioLoopButton.layer.cornerRadius = 10; | |
236 _audioLoopButton.clipsToBounds = YES; | |
237 _audioLoopButton.contentEdgeInsets = UIEdgeInsetsMake(5, 10, 5, 10); | |
238 _audioLoopButton.titleLabel.font = controlFont; | |
239 [_audioLoopButton setTitleColor:[UIColor whiteColor] | |
240 forState:UIControlStateNormal]; | |
241 [_audioLoopButton setTitleColor:[UIColor lightGrayColor] | |
242 forState:UIControlStateSelected]; | |
243 [self updateAudioLoopButton]; | |
244 [_audioLoopButton addTarget:self | |
245 action:@selector(onToggleAudioLoop:) | |
246 forControlEvents:UIControlEventTouchUpInside]; | |
247 [self addSubview:_audioLoopButton]; | |
248 | |
249 self.backgroundColor = [UIColor whiteColor]; | |
250 } | |
251 return self; | |
252 } | |
253 | |
254 - (void)setIsAudioLoopPlaying:(BOOL)isAudioLoopPlaying { | |
255 if (_isAudioLoopPlaying == isAudioLoopPlaying) { | |
256 return; | |
257 } | |
258 _isAudioLoopPlaying = isAudioLoopPlaying; | |
259 [self updateAudioLoopButton]; | |
260 } | |
261 | |
262 - (void)layoutSubviews { | |
263 CGRect bounds = self.bounds; | |
264 CGFloat roomTextWidth = bounds.size.width - 2 * kRoomTextFieldMargin; | |
265 CGFloat roomTextHeight = [_roomText sizeThatFits:bounds.size].height; | |
266 _roomText.frame = CGRectMake(kRoomTextFieldMargin, | |
267 kStatusBarHeight + kRoomTextFieldMargin, | |
268 roomTextWidth, | |
269 roomTextHeight); | |
270 _appLabel.center = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds)); | |
271 | |
272 CGFloat callOptionsLabelTop = | |
273 CGRectGetMaxY(_roomText.frame) + kCallControlMargin * 4; | |
274 _callOptionsLabel.frame = CGRectMake(kCallControlMargin, | |
275 callOptionsLabelTop, | |
276 _callOptionsLabel.frame.size.width, | |
277 _callOptionsLabel.frame.size.height); | |
278 | |
279 CGFloat audioOnlyTop = | |
280 CGRectGetMaxY(_callOptionsLabel.frame) + kCallControlMargin * 2; | |
281 CGRect audioOnlyRect = CGRectMake(kCallControlMargin * 3, | |
282 audioOnlyTop, | |
283 _audioOnlySwitch.frame.size.width, | |
284 _audioOnlySwitch.frame.size.height); | |
285 _audioOnlySwitch.frame = audioOnlyRect; | |
286 CGFloat audioOnlyLabelCenterX = CGRectGetMaxX(audioOnlyRect) + | |
287 kCallControlMargin + _audioOnlyLabel.frame.size.width / 2; | |
288 _audioOnlyLabel.center = CGPointMake(audioOnlyLabelCenterX, | |
289 CGRectGetMidY(audioOnlyRect)); | |
290 | |
291 CGFloat loopbackModeTop = | |
292 CGRectGetMaxY(_audioOnlySwitch.frame) + kCallControlMargin; | |
293 CGRect loopbackModeRect = CGRectMake(kCallControlMargin * 3, | |
294 loopbackModeTop, | |
295 _loopbackSwitch.frame.size.width, | |
296 _loopbackSwitch.frame.size.height); | |
297 _loopbackSwitch.frame = loopbackModeRect; | |
298 CGFloat loopbackModeLabelCenterX = CGRectGetMaxX(loopbackModeRect) + | |
299 kCallControlMargin + _loopbackLabel.frame.size.width / 2; | |
300 _loopbackLabel.center = CGPointMake(loopbackModeLabelCenterX, | |
301 CGRectGetMidY(loopbackModeRect)); | |
302 | |
303 CGFloat aecdumpModeTop = | |
304 CGRectGetMaxY(_loopbackSwitch.frame) + kCallControlMargin; | |
305 CGRect aecdumpModeRect = CGRectMake(kCallControlMargin * 3, | |
306 aecdumpModeTop, | |
307 _aecdumpSwitch.frame.size.width, | |
308 _aecdumpSwitch.frame.size.height); | |
309 _aecdumpSwitch.frame = aecdumpModeRect; | |
310 CGFloat aecdumpModeLabelCenterX = CGRectGetMaxX(aecdumpModeRect) + | |
311 kCallControlMargin + _aecdumpLabel.frame.size.width / 2; | |
312 _aecdumpLabel.center = CGPointMake(aecdumpModeLabelCenterX, | |
313 CGRectGetMidY(aecdumpModeRect)); | |
314 | |
315 CGFloat levelControlModeTop = | |
316 CGRectGetMaxY(_aecdumpSwitch.frame) + kCallControlMargin; | |
317 CGRect levelControlModeRect = CGRectMake(kCallControlMargin * 3, | |
318 levelControlModeTop, | |
319 _levelControlSwitch.frame.size.width, | |
320 _levelControlSwitch.frame.size.height
); | |
321 _levelControlSwitch.frame = levelControlModeRect; | |
322 CGFloat levelControlModeLabelCenterX = CGRectGetMaxX(levelControlModeRect) + | |
323 kCallControlMargin + _levelControlLabel.frame.size.width / 2; | |
324 _levelControlLabel.center = CGPointMake(levelControlModeLabelCenterX, | |
325 CGRectGetMidY(levelControlModeRect)); | |
326 | |
327 CGFloat useManualAudioTop = | |
328 CGRectGetMaxY(_levelControlSwitch.frame) + kCallControlMargin; | |
329 CGRect useManualAudioRect = | |
330 CGRectMake(kCallControlMargin * 3, | |
331 useManualAudioTop, | |
332 _useManualAudioSwitch.frame.size.width, | |
333 _useManualAudioSwitch.frame.size.height); | |
334 _useManualAudioSwitch.frame = useManualAudioRect; | |
335 CGFloat useManualAudioLabelCenterX = CGRectGetMaxX(useManualAudioRect) + | |
336 kCallControlMargin + _useManualAudioLabel.frame.size.width / 2; | |
337 _useManualAudioLabel.center = | |
338 CGPointMake(useManualAudioLabelCenterX, | |
339 CGRectGetMidY(useManualAudioRect)); | |
340 | |
341 CGFloat audioLoopTop = | |
342 CGRectGetMaxY(useManualAudioRect) + kCallControlMargin * 3; | |
343 _audioLoopButton.frame = CGRectMake(kCallControlMargin, | |
344 audioLoopTop, | |
345 _audioLoopButton.frame.size.width, | |
346 _audioLoopButton.frame.size.height); | |
347 | |
348 CGFloat startCallTop = | |
349 CGRectGetMaxY(_audioLoopButton.frame) + kCallControlMargin * 3; | |
350 _startCallButton.frame = CGRectMake(kCallControlMargin, | |
351 startCallTop, | |
352 _startCallButton.frame.size.width, | |
353 _startCallButton.frame.size.height); | |
354 } | |
355 | |
356 #pragma mark - Private | |
357 | |
358 - (void)updateAudioLoopButton { | |
359 if (_isAudioLoopPlaying) { | |
360 _audioLoopButton.backgroundColor = [UIColor redColor]; | |
361 [_audioLoopButton setTitle:@"Stop sound" | |
362 forState:UIControlStateNormal]; | |
363 [_audioLoopButton sizeToFit]; | |
364 } else { | |
365 _audioLoopButton.backgroundColor = [UIColor greenColor]; | |
366 [_audioLoopButton setTitle:@"Play sound" | |
367 forState:UIControlStateNormal]; | |
368 [_audioLoopButton sizeToFit]; | |
369 } | |
370 } | |
371 | |
372 - (void)onToggleAudioLoop:(id)sender { | |
373 [_delegate mainViewDidToggleAudioLoop:self]; | |
374 } | |
375 | |
376 - (void)onStartCall:(id)sender { | |
377 NSString *room = _roomText.roomText; | |
378 // If this is a loopback call, allow a generated room name. | |
379 if (!room.length && _loopbackSwitch.isOn) { | |
380 room = [[NSUUID UUID] UUIDString]; | |
381 } | |
382 room = [room stringByReplacingOccurrencesOfString:@"-" withString:@""]; | |
383 [_delegate mainView:self | |
384 didInputRoom:room | |
385 isLoopback:_loopbackSwitch.isOn | |
386 isAudioOnly:_audioOnlySwitch.isOn | |
387 shouldMakeAecDump:_aecdumpSwitch.isOn | |
388 shouldUseLevelControl:_levelControlSwitch.isOn | |
389 useManualAudio:_useManualAudioSwitch.isOn]; | |
390 } | |
391 | |
392 @end | |
OLD | NEW |