diff --git a/iOS/GBViewController.m b/iOS/GBViewController.m index 725a3eef3..3c6926b1f 100644 --- a/iOS/GBViewController.m +++ b/iOS/GBViewController.m @@ -52,10 +52,10 @@ NSTimer *_disableCameraTimer; AVCaptureDevicePosition _cameraPosition; UIButton *_cameraPositionButton; + UIButton *_changeCameraButton; NSArray *_allCaptureDevices; NSArray *_backCaptureDevices; - AVCaptureDevice *_selectedCaptureDevice; - UIButton *_changeCameraButton; + AVCaptureDevice *_selectedBackCaptureDevice; __weak GCController *_lastController; @@ -245,7 +245,7 @@ static void rumbleCallback(GB_gameboy_t *gb, double amp) _motionManager = [[CMMotionManager alloc] init]; _cameraPosition = AVCaptureDevicePositionBack; - _selectedCaptureDevice = [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeVideo]; + _selectedBackCaptureDevice = [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeVideo]; // Back camera setup NSArray *deviceTypes = @[AVCaptureDeviceTypeBuiltInWideAngleCamera, @@ -273,8 +273,9 @@ static void rumbleCallback(GB_gameboy_t *gb, double amp) } _backCaptureDevices = filteredBackCameras; - _cameraPositionButton = [[UIButton alloc] initWithFrame:CGRectMake(8, - 0, + UIEdgeInsets insets = self.window.safeAreaInsets; + _cameraPositionButton = [[UIButton alloc] initWithFrame:CGRectMake(insets.left + 8, + _backgroundView.bounds.size.height - 8 - insets.bottom - 32, 32, 32)]; [self didRotateFromInterfaceOrientation:[UIApplication sharedApplication].statusBarOrientation]; @@ -284,20 +285,20 @@ static void rumbleCallback(GB_gameboy_t *gb, double amp) forState:UIControlStateNormal]; _cameraPositionButton.backgroundColor = [UIColor systemBackgroundColor]; - // Configure the change camera button - _changeCameraButton = [[UIButton alloc] initWithFrame:CGRectMake(8, - 0, + // Configure the change camera button stacked on top of the camera position button + _changeCameraButton = [[UIButton alloc] initWithFrame:CGRectMake(insets.left + 8, + _backgroundView.bounds.size.height - 8 - insets.bottom - 32 - 32 - 8, 32, 32)]; - [_changeCameraButton setImage:[UIImage systemImageNamed:@"camera" + [_changeCameraButton setImage:[UIImage systemImageNamed:@"camera.aperture" withConfiguration:[UIImageSymbolConfiguration configurationWithScale:UIImageSymbolScaleLarge]] forState:UIControlStateNormal]; _changeCameraButton.backgroundColor = [UIColor systemBackgroundColor]; _changeCameraButton.layer.cornerRadius = 6; _changeCameraButton.alpha = 0; [_changeCameraButton addTarget:self - action:@selector(changeCamera) - forControlEvents:UIControlEventTouchUpInside]; + action:@selector(changeCamera) + forControlEvents:UIControlEventTouchUpInside]; // Only show the change camera button if we have more than one back camera to swap between. if ([_backCaptureDevices count] > 1) { [_backgroundView addSubview:_changeCameraButton]; @@ -309,11 +310,12 @@ static void rumbleCallback(GB_gameboy_t *gb, double amp) forState:UIControlStateNormal]; _cameraPositionButton.backgroundColor = [UIColor whiteColor]; } + _cameraPositionButton.layer.cornerRadius = 6; _cameraPositionButton.alpha = 0; [_cameraPositionButton addTarget:self - action:@selector(rotateCamera) - forControlEvents:UIControlEventTouchUpInside]; + action:@selector(rotateCamera) + forControlEvents:UIControlEventTouchUpInside]; [_backgroundView addSubview:_cameraPositionButton]; @@ -737,9 +739,15 @@ static void rumbleCallback(GB_gameboy_t *gb, double amp) - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { UIEdgeInsets insets = self.window.safeAreaInsets; - _cameraPositionButton.frame = CGRectMake(insets.left + 8, _backgroundView.bounds.size.height - 8 - insets.bottom - 32, 32, 32); - if (@available(iOS 13.0, *)) { - _changeCameraButton.frame = CGRectMake(_backgroundView.bounds.size.width - 8 - insets.right - 32, _backgroundView.bounds.size.height - 8 - insets.bottom - 32, 32, 32); + _cameraPositionButton.frame = CGRectMake(insets.left + 8, + _backgroundView.bounds.size.height - 8 - insets.bottom - 32, + 32, + 32); + if (_changeCameraButton != nil) { + _changeCameraButton.frame = CGRectMake(insets.left + 8, + _backgroundView.bounds.size.height - 8 - insets.bottom - 32 - 32 - 8, + 32, + 32); } } @@ -1186,7 +1194,7 @@ didReceiveNotificationResponse:(UNNotificationResponse *)response } // There may be several back cameras, return the one with the matching type - if ([device deviceType] == [_selectedCaptureDevice deviceType]) { + if ([device deviceType] == [_selectedBackCaptureDevice deviceType]) { return device; } } @@ -1242,6 +1250,14 @@ didReceiveNotificationResponse:(UNNotificationResponse *)response _cameraPositionButton.alpha = 1; }]; } + if (_changeCameraButton != nil) { + // The change camera button is only available when we are using a capture device on the back of the device + int changeCameraButtonAlpha = (_cameraPosition == AVCaptureDevicePositionFront) ? 0 : 1; + [UIView animateWithDuration:0.25 animations:^{ + _changeCameraButton.alpha = changeCameraButtonAlpha; + }]; + } + _disableCameraTimer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:false block:^(NSTimer *timer) { @@ -1250,6 +1266,13 @@ didReceiveNotificationResponse:(UNNotificationResponse *)response _cameraPositionButton.alpha = 0; }]; } + if (_changeCameraButton != nil) { + if (_changeCameraButton.alpha) { + [UIView animateWithDuration:0.25 animations:^{ + _changeCameraButton.alpha = 0; + }]; + } + } dispatch_async(_cameraQueue, ^{ [_cameraSession stopRunning]; _cameraSession = nil; @@ -1359,9 +1382,9 @@ didReceiveNotificationResponse:(UNNotificationResponse *)response { dispatch_async(_cameraQueue, ^{ // Get index of selected camera and select the next one, wrapping to the beginning - NSUInteger i = [_backCaptureDevices indexOfObject:_selectedCaptureDevice]; + NSUInteger i = [_backCaptureDevices indexOfObject:_selectedBackCaptureDevice]; int nextIndex = (i + 1) % _backCaptureDevices.count; - _selectedCaptureDevice = _backCaptureDevices[nextIndex]; + _selectedBackCaptureDevice = _backCaptureDevices[nextIndex]; [_cameraSession stopRunning]; _cameraSession = nil;