From 4c689db8ee838df1c06ab4d8b7a212fcf0924c50 Mon Sep 17 00:00:00 2001 From: Vadim <44135514+vodemn@users.noreply.github.com> Date: Sun, 11 May 2025 12:48:10 +0200 Subject: [PATCH] split other platform handlers to separate files --- .../com/vodemn/lightmeter/MainActivity.kt | 85 +++---------------- .../CaffeinePlatformChannel.kt | 42 +++++++++ .../CameraInfoPlatformChannel.kt | 26 +++--- .../PlatformChannels/VolumePlatformChannel.kt | 66 ++++++++++++++ ios/Runner/AppDelegate.swift | 20 +---- .../CaffeinePlatformChannel.swift | 36 ++++++++ lib/application_wrapper.dart | 4 +- lib/data/caffeine_service.dart | 8 +- lib/data/camera_info_service.dart | 4 +- lib/data/volume_events_service.dart | 13 +-- test/data/caffeine_service_test.dart | 65 ++++++++------ test/data/volume_events_service_test.dart | 4 +- 12 files changed, 226 insertions(+), 147 deletions(-) create mode 100644 android/app/src/main/kotlin/com/vodemn/lightmeter/PlatformChannels/CaffeinePlatformChannel.kt create mode 100644 android/app/src/main/kotlin/com/vodemn/lightmeter/PlatformChannels/VolumePlatformChannel.kt create mode 100644 ios/Runner/PlatformChannels/CaffeinePlatformChannel.swift diff --git a/android/app/src/main/kotlin/com/vodemn/lightmeter/MainActivity.kt b/android/app/src/main/kotlin/com/vodemn/lightmeter/MainActivity.kt index 194ec17..e120f88 100644 --- a/android/app/src/main/kotlin/com/vodemn/lightmeter/MainActivity.kt +++ b/android/app/src/main/kotlin/com/vodemn/lightmeter/MainActivity.kt @@ -2,23 +2,17 @@ package com.vodemn.lightmeter import android.os.Bundle import android.view.KeyEvent -import android.view.WindowManager import androidx.core.view.WindowCompat +import com.vodemn.lightmeter.PlatformChannels.CaffeinePlatformChannel import com.vodemn.lightmeter.PlatformChannels.CameraInfoPlatformChannel +import com.vodemn.lightmeter.PlatformChannels.VolumePlatformChannel import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugin.common.EventChannel -import io.flutter.plugin.common.EventChannel.EventSink -import io.flutter.plugin.common.MethodChannel class MainActivity : FlutterActivity() { - private lateinit var keepScreenOnChannel: MethodChannel - private lateinit var volumeHandlingChannel: MethodChannel - private lateinit var volumeEventChannel: EventChannel - private var volumeEventsEmitter: EventSink? = null - private var handleVolume = false - + private val caffeinePlatformChannel = CaffeinePlatformChannel() private val cameraInfoPlatformChannel = CameraInfoPlatformChannel() + private val volumePlatformChannel = VolumePlatformChannel() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -27,75 +21,24 @@ class MainActivity : FlutterActivity() { override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) - cameraInfoPlatformChannel.onAttachedToEngine(flutterEngine.dartExecutor.binaryMessenger, context) - - keepScreenOnChannel = MethodChannel( - flutterEngine.dartExecutor.binaryMessenger, - "com.vodemn.lightmeter/keepScreenOn" - ) - keepScreenOnChannel.setMethodCallHandler { call, result -> - when (call.method) { - "isKeepScreenOn" -> result.success((window.attributes.flags and WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0) - "setKeepScreenOn" -> { - if (call.arguments !is Boolean) { - result.error("invalid args", "Argument should be of type Bool for 'setKeepScreenOn' call", null) - } else { - if (call.arguments as Boolean) window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) - else window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) - result.success(true) - } - } - else -> result.notImplemented() - } - } - - volumeHandlingChannel = MethodChannel( - flutterEngine.dartExecutor.binaryMessenger, - "com.vodemn.lightmeter/volumeHandling" - ) - volumeHandlingChannel.setMethodCallHandler { call, result -> - when (call.method) { - "setVolumeHandling" -> { - handleVolume = call.arguments as Boolean - result.success(handleVolume) - } - else -> result.notImplemented() - } - } - - volumeEventChannel = EventChannel( - flutterEngine.dartExecutor.binaryMessenger, - "com.vodemn.lightmeter/volumeEvents" - ) - volumeEventChannel.setStreamHandler(object : EventChannel.StreamHandler { - override fun onListen(listener: Any?, eventSink: EventSink) { - volumeEventsEmitter = eventSink - } - override fun onCancel(listener: Any?) { - volumeEventsEmitter = null - } - }) + val binaryMessenger = flutterEngine.dartExecutor.binaryMessenger + caffeinePlatformChannel.onAttachedToEngine(binaryMessenger, window) + cameraInfoPlatformChannel.onAttachedToEngine(binaryMessenger, context) + volumePlatformChannel.onAttachedToEngine(binaryMessenger) } override fun onDestroy() { - keepScreenOnChannel.setMethodCallHandler(null) - volumeHandlingChannel.setMethodCallHandler(null) - volumeEventChannel.setStreamHandler(null) + caffeinePlatformChannel.onDestroy() cameraInfoPlatformChannel.onDestroy() + volumePlatformChannel.onDestroy() super.onDestroy() } override fun onKeyDown(code: Int, event: KeyEvent): Boolean { - return when (val keyCode: Int = event.keyCode) { - KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_VOLUME_DOWN -> { - if (handleVolume) { - volumeEventsEmitter?.success(keyCode) - true - } else { - super.onKeyDown(code, event) - } - } - else -> super.onKeyDown(code, event) + return if (volumePlatformChannel.onKeyDown(code, event)) { + true + } else { + super.onKeyDown(code, event) } } } diff --git a/android/app/src/main/kotlin/com/vodemn/lightmeter/PlatformChannels/CaffeinePlatformChannel.kt b/android/app/src/main/kotlin/com/vodemn/lightmeter/PlatformChannels/CaffeinePlatformChannel.kt new file mode 100644 index 0000000..233831f --- /dev/null +++ b/android/app/src/main/kotlin/com/vodemn/lightmeter/PlatformChannels/CaffeinePlatformChannel.kt @@ -0,0 +1,42 @@ +package com.vodemn.lightmeter.PlatformChannels + +import android.view.Window +import android.view.WindowManager +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.MethodChannel + +/** CaffeinePlatformChannel */ +class CaffeinePlatformChannel { + private lateinit var channel: MethodChannel + + fun onAttachedToEngine(binaryMessenger: BinaryMessenger, window: Window) { + channel = MethodChannel( + binaryMessenger, + "com.vodemn.lightmeter.CaffeinePlatformChannel.MethodChannel" + ) + channel.setMethodCallHandler { call, result -> + when (call.method) { + "isKeepScreenOn" -> result.success((window.attributes.flags and WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0) + "setKeepScreenOn" -> { + if (call.arguments !is Boolean) { + result.error( + "invalid args", + "Argument should be of type Bool for 'setKeepScreenOn' call", + null + ) + } else { + if (call.arguments as Boolean) window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + else window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + result.success(true) + } + } + + else -> result.notImplemented() + } + } + } + + fun onDestroy() { + channel.setMethodCallHandler(null) + } +} diff --git a/android/app/src/main/kotlin/com/vodemn/lightmeter/PlatformChannels/CameraInfoPlatformChannel.kt b/android/app/src/main/kotlin/com/vodemn/lightmeter/PlatformChannels/CameraInfoPlatformChannel.kt index 53d9f07..be831b1 100644 --- a/android/app/src/main/kotlin/com/vodemn/lightmeter/PlatformChannels/CameraInfoPlatformChannel.kt +++ b/android/app/src/main/kotlin/com/vodemn/lightmeter/PlatformChannels/CameraInfoPlatformChannel.kt @@ -5,30 +5,31 @@ import android.hardware.camera2.CameraCharacteristics import android.hardware.camera2.CameraManager import android.hardware.camera2.CameraMetadata.LENS_FACING_BACK import io.flutter.plugin.common.BinaryMessenger -import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel import kotlin.math.pow import kotlin.math.sqrt /** CameraInfoPlatformChannel */ -class CameraInfoPlatformChannel : MethodChannel.MethodCallHandler { +class CameraInfoPlatformChannel { private lateinit var channel: MethodChannel private lateinit var cameraManager: CameraManager private var mainCameraEfl: Double? = null fun onAttachedToEngine(binaryMessenger: BinaryMessenger, context: Context) { - channel = MethodChannel(binaryMessenger, "com.vodemn.lightmeter.CameraInfoPlatformChannel") + channel = MethodChannel( + binaryMessenger, + "com.vodemn.lightmeter.CameraInfoPlatformChannel.MethodChannel" + ) cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager - channel.setMethodCallHandler(this) - } + channel.setMethodCallHandler { call, result -> + when (call.method) { + "mainCameraEfl" -> { + mainCameraEfl = mainCameraEfl ?: getMainCameraFocalLength35mm() + result.success(mainCameraEfl) + } - override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { - when (call.method) { - "mainCameraEfl" -> { - mainCameraEfl = mainCameraEfl ?: getMainCameraFocalLength35mm() - result.success(mainCameraEfl) + else -> result.notImplemented() } - else -> result.notImplemented() } } @@ -45,7 +46,8 @@ class CameraInfoPlatformChannel : MethodChannel.MethodCallHandler { } private fun CameraCharacteristics.focalLength35mm(): Double? { - val defaultFocalLength = get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS)?.first() + val defaultFocalLength = + get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS)?.first() val sensorSize = get(CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE) return if (defaultFocalLength != null && sensorSize != null) { // https://en.wikipedia.org/wiki/35_mm_equivalent_focal_length#Conversions diff --git a/android/app/src/main/kotlin/com/vodemn/lightmeter/PlatformChannels/VolumePlatformChannel.kt b/android/app/src/main/kotlin/com/vodemn/lightmeter/PlatformChannels/VolumePlatformChannel.kt new file mode 100644 index 0000000..d9759d4 --- /dev/null +++ b/android/app/src/main/kotlin/com/vodemn/lightmeter/PlatformChannels/VolumePlatformChannel.kt @@ -0,0 +1,66 @@ +package com.vodemn.lightmeter.PlatformChannels + +import android.view.KeyEvent +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.EventChannel +import io.flutter.plugin.common.EventChannel.EventSink +import io.flutter.plugin.common.MethodChannel + +/** VolumePlatformChannel */ +class VolumePlatformChannel { + private lateinit var volumeMethodChannel: MethodChannel + private lateinit var volumeEventChannel: EventChannel + private var volumeEventsEmitter: EventSink? = null + private var handleVolume = false + + fun onAttachedToEngine(binaryMessenger: BinaryMessenger) { + volumeMethodChannel = MethodChannel( + binaryMessenger, + "com.vodemn.lightmeter.VolumePlatformChannel.MethodChannel" + ) + volumeMethodChannel.setMethodCallHandler { call, result -> + when (call.method) { + "setVolumeHandling" -> { + handleVolume = call.arguments as Boolean + result.success(handleVolume) + } + + else -> result.notImplemented() + } + } + + volumeEventChannel = EventChannel( + binaryMessenger, + "com.vodemn.lightmeter.VolumePlatformChannel.EventChannel" + ) + volumeEventChannel.setStreamHandler(object : EventChannel.StreamHandler { + override fun onListen(listener: Any?, eventSink: EventSink) { + volumeEventsEmitter = eventSink + } + + override fun onCancel(listener: Any?) { + volumeEventsEmitter = null + } + }) + } + + fun onDestroy() { + volumeMethodChannel.setMethodCallHandler(null) + volumeEventChannel.setStreamHandler(null) + } + + fun onKeyDown(code: Int, event: KeyEvent): Boolean { + return when (val keyCode: Int = event.keyCode) { + KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_VOLUME_DOWN -> { + if (handleVolume) { + volumeEventsEmitter?.success(keyCode) + true + } else { + false + } + } + + else -> false + } + } +} \ No newline at end of file diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index b43b14e..6aaa67a 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -8,25 +8,7 @@ import Flutter didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { let controller : FlutterViewController = window?.rootViewController as! FlutterViewController - let keepScreenOnChannel = FlutterMethodChannel(name: "com.vodemn.lightmeter/keepScreenOn", - binaryMessenger: controller.binaryMessenger) - keepScreenOnChannel.setMethodCallHandler({ - (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in - switch call.method { - case "isKeepScreenOn": - result(UIApplication.shared.isIdleTimerDisabled) - case "setKeepScreenOn": - guard let keepOn = call.arguments as? Bool else { - result(FlutterError(code: "invalid arguments", message: "Argument should be of type Bool for 'setKeepScreenOn' call", details: nil)) - return - } - UIApplication.shared.isIdleTimerDisabled = keepOn - result(true) - default: - result(FlutterMethodNotImplemented) - } - }) - + let caffeinePlatformChannel = CaffeinePlatformChannel(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 new file mode 100644 index 0000000..251cd1a --- /dev/null +++ b/ios/Runner/PlatformChannels/CaffeinePlatformChannel.swift @@ -0,0 +1,36 @@ +// +// CaffeinePlatformChannel.swift +// Runner +// +// Created by Vadim Turko on 2025-05-11. +// +import Flutter + +public class CaffeinePlatformChannel: NSObject { + let methodChannel: FlutterMethodChannel + + init(binaryMessenger: FlutterBinaryMessenger) { + self.methodChannel = FlutterMethodChannel( + name: "com.vodemn.lightmeter.CaffeinePlatformChannel.MethodChannel", + binaryMessenger: binaryMessenger + ) + super.init() + methodChannel.setMethodCallHandler({ + (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in + switch call.method { + case "isKeepScreenOn": + result(UIApplication.shared.isIdleTimerDisabled) + case "setKeepScreenOn": + guard let keepOn = call.arguments as? Bool else { + result(FlutterError(code: "invalid arguments", message: "Argument should be of type Bool for 'setKeepScreenOn' call", details: nil)) + return + } + UIApplication.shared.isIdleTimerDisabled = keepOn + result(true) + default: + result(FlutterMethodNotImplemented) + } + }) + + } +} diff --git a/lib/application_wrapper.dart b/lib/application_wrapper.dart index e2c6136..ba6dbdd 100644 --- a/lib/application_wrapper.dart +++ b/lib/application_wrapper.dart @@ -100,13 +100,11 @@ 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?)!) - ..cameraFocalLength = value[2] as int?; + userPreferencesService = UserPreferencesService((value[0] as SharedPreferences?)!); hasLightSensor = value[1] as bool? ?? false; }); } diff --git a/lib/data/caffeine_service.dart b/lib/data/caffeine_service.dart index da36968..106438d 100644 --- a/lib/data/caffeine_service.dart +++ b/lib/data/caffeine_service.dart @@ -1,15 +1,17 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; class CaffeineService { - static const _methodChannel = MethodChannel("com.vodemn.lightmeter/keepScreenOn"); + @visibleForTesting + static const caffeineMethodChannel = MethodChannel("com.vodemn.lightmeter.CaffeinePlatformChannel.MethodChannel"); const CaffeineService(); Future isKeepScreenOn() async { - return _methodChannel.invokeMethod("isKeepScreenOn").then((value) => value!); + return caffeineMethodChannel.invokeMethod("isKeepScreenOn").then((value) => value!); } Future keepScreenOn(bool keep) async { - return _methodChannel.invokeMethod("setKeepScreenOn", keep).then((value) => value!); + return caffeineMethodChannel.invokeMethod("setKeepScreenOn", keep).then((value) => value!); } } diff --git a/lib/data/camera_info_service.dart b/lib/data/camera_info_service.dart index 351a975..5965186 100644 --- a/lib/data/camera_info_service.dart +++ b/lib/data/camera_info_service.dart @@ -5,7 +5,9 @@ import 'package:flutter/services.dart'; class CameraInfoService { @visibleForTesting - static const cameraInfoPlatformChannel = MethodChannel("com.vodemn.lightmeter.CameraInfoPlatformChannel"); + static const cameraInfoPlatformChannel = MethodChannel( + "com.vodemn.lightmeter.CameraInfoPlatformChannel.MethodChannel", + ); const CameraInfoService(); diff --git a/lib/data/volume_events_service.dart b/lib/data/volume_events_service.dart index 360de75..7dfde55 100644 --- a/lib/data/volume_events_service.dart +++ b/lib/data/volume_events_service.dart @@ -6,10 +6,10 @@ class VolumeEventsService { final LocalPlatform _localPlatform; @visibleForTesting - static const volumeHandlingChannel = MethodChannel("com.vodemn.lightmeter/volumeHandling"); + static const volumeMethodChannel = MethodChannel("com.vodemn.lightmeter.VolumePlatformChannel.MethodChannel"); @visibleForTesting - static const volumeEventsChannel = EventChannel("com.vodemn.lightmeter/volumeEvents"); + static const volumeEventsChannel = EventChannel("com.vodemn.lightmeter.VolumePlatformChannel.EventChannel"); const VolumeEventsService(this._localPlatform); @@ -19,9 +19,7 @@ class VolumeEventsService { if (!_localPlatform.isAndroid) { return false; } - return volumeHandlingChannel - .invokeMethod("setVolumeHandling", enableHandling) - .then((value) => value!); + return volumeMethodChannel.invokeMethod("setVolumeHandling", enableHandling).then((value) => value!); } /// Emits new events on @@ -32,9 +30,6 @@ class VolumeEventsService { if (!_localPlatform.isAndroid) { return const Stream.empty(); } - return volumeEventsChannel - .receiveBroadcastStream() - .cast() - .where((event) => event == 24 || event == 25); + return volumeEventsChannel.receiveBroadcastStream().cast().where((event) => event == 24 || event == 25); } } diff --git a/test/data/caffeine_service_test.dart b/test/data/caffeine_service_test.dart index 0c80fac..fddfce1 100644 --- a/test/data/caffeine_service_test.dart +++ b/test/data/caffeine_service_test.dart @@ -7,7 +7,6 @@ void main() { late CaffeineService service; - const methodChannel = MethodChannel('com.vodemn.lightmeter/keepScreenOn'); Future? methodCallSuccessHandler(MethodCall methodCall) async { switch (methodCall.method) { case "isKeepScreenOn": @@ -21,45 +20,57 @@ void main() { setUp(() { service = const CaffeineService(); - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler(methodChannel, methodCallSuccessHandler); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler( + CaffeineService.caffeineMethodChannel, + methodCallSuccessHandler, + ); }); tearDown(() { - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler(methodChannel, null); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler( + CaffeineService.caffeineMethodChannel, + null, + ); }); group( 'isKeepScreenOn()', () { test('true', () async { - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler(methodChannel, null); - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler(methodChannel, (methodCall) async { - switch (methodCall.method) { - case "isKeepScreenOn": - return true; - default: - return null; - } - }); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler( + CaffeineService.caffeineMethodChannel, + null, + ); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler( + CaffeineService.caffeineMethodChannel, + (methodCall) async { + switch (methodCall.method) { + case "isKeepScreenOn": + return true; + default: + return null; + } + }, + ); expectLater(service.isKeepScreenOn(), completion(true)); }); test('false', () async { - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler(methodChannel, null); - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler(methodChannel, (methodCall) async { - switch (methodCall.method) { - case "isKeepScreenOn": - return false; - default: - return null; - } - }); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler( + CaffeineService.caffeineMethodChannel, + null, + ); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler( + CaffeineService.caffeineMethodChannel, + (methodCall) async { + switch (methodCall.method) { + case "isKeepScreenOn": + return false; + default: + return null; + } + }, + ); expectLater(service.isKeepScreenOn(), completion(false)); }); }, diff --git a/test/data/volume_events_service_test.dart b/test/data/volume_events_service_test.dart index f574e50..8dc994c 100644 --- a/test/data/volume_events_service_test.dart +++ b/test/data/volume_events_service_test.dart @@ -27,14 +27,14 @@ void main() { localPlatform = _MockLocalPlatform(); service = VolumeEventsService(localPlatform); TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler( - VolumeEventsService.volumeHandlingChannel, + VolumeEventsService.volumeMethodChannel, methodCallSuccessHandler, ); }); tearDown(() { TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler( - VolumeEventsService.volumeHandlingChannel, + VolumeEventsService.volumeMethodChannel, null, ); });