diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 6aaa67a..d385809 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -9,6 +9,7 @@ import Flutter ) -> Bool { let controller : FlutterViewController = window?.rootViewController as! FlutterViewController let caffeinePlatformChannel = CaffeinePlatformChannel(binaryMessenger: controller.binaryMessenger) + let cameraInfoPlatformChannel = CameraInfoPlatformChannel(binaryMessenger: controller.binaryMessenger) GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } diff --git a/ios/Runner/PlatformChannels/CaffeinePlatformChannel.swift b/ios/Runner/PlatformChannels/CaffeinePlatformChannel.swift index 251cd1a..7268a0c 100644 --- a/ios/Runner/PlatformChannels/CaffeinePlatformChannel.swift +++ b/ios/Runner/PlatformChannels/CaffeinePlatformChannel.swift @@ -31,6 +31,5 @@ public class CaffeinePlatformChannel: NSObject { result(FlutterMethodNotImplemented) } }) - } } diff --git a/ios/Runner/PlatformChannels/CameraInfoPlatformChannel.swift b/ios/Runner/PlatformChannels/CameraInfoPlatformChannel.swift new file mode 100644 index 0000000..e2922b0 --- /dev/null +++ b/ios/Runner/PlatformChannels/CameraInfoPlatformChannel.swift @@ -0,0 +1,45 @@ +// +// CameraInfoPlatformChannel.swift +// Runner +// +// Created by Vadim Turko on 2025-05-11. +// +import AVFoundation +import Flutter + +public class CameraInfoPlatformChannel: NSObject { + let methodChannel: FlutterMethodChannel + + init(binaryMessenger: FlutterBinaryMessenger) { + self.methodChannel = FlutterMethodChannel( + name: "com.vodemn.lightmeter.CameraInfoPlatformChannel.MethodChannel", + binaryMessenger: binaryMessenger + ) + super.init() + methodChannel.setMethodCallHandler({ + (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in + switch call.method { + case "mainCameraEfl": + if let device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back) { + result(self.get35mmEquivalentFocalLength(format: device.activeFormat)) + } else { + result(nil) + } + default: + result(FlutterMethodNotImplemented) + } + }) + } + + func get35mmEquivalentFocalLength(format : AVCaptureDevice.Format) -> Float { + // get reported field of view. Documentation says this is the horizontal field of view + var fov = format.videoFieldOfView + // convert to radians + fov *= Float.pi/180.0 + // angle and opposite of right angle triangle are half the fov and half the width of + // 35mm film (ie 18mm). The adjacent value of the right angle triangle is the equivalent + // focal length. Using some right angle triangle math you can work out focal length + let focalLen = 18 / tan(fov/2) + return focalLen + } +} diff --git a/lib/application_wrapper.dart b/lib/application_wrapper.dart index ba6dbdd..e2c6136 100644 --- a/lib/application_wrapper.dart +++ b/lib/application_wrapper.dart @@ -100,11 +100,13 @@ class _ApplicationWrapperState extends State { await Future.wait([ SharedPreferences.getInstance(), const LightSensorService(LocalPlatform()).hasSensor(), + const CameraInfoService().mainCameraEfl(), remoteConfigService.activeAndFetchFeatures(), equipmentProfilesStorageService.init(), filmsStorageService.init(), ]).then((value) { - userPreferencesService = UserPreferencesService((value[0] as SharedPreferences?)!); + userPreferencesService = UserPreferencesService((value[0] as SharedPreferences?)!) + ..cameraFocalLength = value[2] as int?; hasLightSensor = value[1] as bool? ?? false; }); } diff --git a/lib/data/camera_info_service.dart b/lib/data/camera_info_service.dart index 5965186..44819b6 100644 --- a/lib/data/camera_info_service.dart +++ b/lib/data/camera_info_service.dart @@ -1,5 +1,3 @@ -import 'dart:io'; - import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; @@ -12,9 +10,7 @@ class CameraInfoService { const CameraInfoService(); Future mainCameraEfl() async { - if (Platform.isIOS) { - return null; - } - return (await cameraInfoPlatformChannel.invokeMethod('mainCameraEfl'))?.round(); + final focalLength = await cameraInfoPlatformChannel.invokeMethod('mainCameraEfl'); + return focalLength?.round(); } }