diff --git a/lib/app/modules/timer/controllers/timer_controller.dart b/lib/app/modules/timer/controllers/timer_controller.dart index d17cf5fdd..6070c7963 100644 --- a/lib/app/modules/timer/controllers/timer_controller.dart +++ b/lib/app/modules/timer/controllers/timer_controller.dart @@ -6,21 +6,23 @@ import 'package:ultimate_alarm_clock/app/data/models/timer_model.dart'; import 'package:ultimate_alarm_clock/app/data/providers/isar_provider.dart'; import 'package:ultimate_alarm_clock/app/utils/utils.dart'; - class LimitRange extends TextInputFormatter { LimitRange(this.minRange, this.maxRange) : assert(minRange < maxRange); final int minRange; final int maxRange; @override - TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) { + TextEditingValue formatEditUpdate( + TextEditingValue oldValue, TextEditingValue newValue) { try { if (newValue.text.isEmpty) { return newValue; } int value = int.parse(newValue.text); - if (value < minRange) return TextEditingValue(text: minRange.toString()); - else if (value > maxRange) return TextEditingValue(text: maxRange.toString()); + if (value < minRange) + return TextEditingValue(text: minRange.toString()); + else if (value > maxRange) + return TextEditingValue(text: maxRange.toString()); return newValue; } catch (e) { debugPrint(e.toString()); @@ -40,21 +42,20 @@ class TimerController extends FullLifeCycleController with FullLifeCycleMixin { ScrollController scrollController = ScrollController(); RxList timers = [].obs; RxList isRinging = [].obs; - - - final TextEditingController inputHoursControllerTimer = TextEditingController(text: '0'); - final TextEditingController inputMinutesControllerTimer = TextEditingController(text: '1'); - final TextEditingController inputSecondsControllerTimer = TextEditingController(text: '0'); - - + + final TextEditingController inputHoursControllerTimer = + TextEditingController(text: '0'); + final TextEditingController inputMinutesControllerTimer = + TextEditingController(text: '1'); + final TextEditingController inputSecondsControllerTimer = + TextEditingController(text: '0'); + final isTimePickerTimer = false.obs; - - + void changeTimePickerTimer() { isTimePickerTimer.value = !isTimePickerTimer.value; } - - + void setTimerTime() { try { int hours = int.parse(inputHoursControllerTimer.text); @@ -68,7 +69,6 @@ class TimerController extends FullLifeCycleController with FullLifeCycleMixin { } } - void setTextFieldTimerTime() { inputHoursControllerTimer.text = hours.value.toString(); inputMinutesControllerTimer.text = minutes.value.toString(); @@ -162,7 +162,7 @@ class TimerController extends FullLifeCycleController with FullLifeCycleMixin { } cancelTimer() async { - await timerChannel.invokeMethod('cancelTimer'); + await timerChannel.invokeMethod('clearTimerNotif'); } @override @@ -195,8 +195,9 @@ class TimerController extends FullLifeCycleController with FullLifeCycleMixin { Get.back(); } } + Future setPresetTimer(Duration presetDuration) async { - remainingTime.value = presetDuration; - await createTimer(); -} + remainingTime.value = presetDuration; + await createTimer(); + } } diff --git a/lib/app/modules/timerRing/controllers/timer_ring_controller.dart b/lib/app/modules/timerRing/controllers/timer_ring_controller.dart index 045220c26..9659b1ae1 100644 --- a/lib/app/modules/timerRing/controllers/timer_ring_controller.dart +++ b/lib/app/modules/timerRing/controllers/timer_ring_controller.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter_fgbg/flutter_fgbg.dart'; import 'package:get/get.dart'; @@ -10,12 +11,14 @@ import 'package:vibration/vibration.dart'; class TimerRingController extends GetxController { MethodChannel timerChannel = const MethodChannel('timer'); + MethodChannel alarmChannel = const MethodChannel('ulticlock'); Timer? vibrationTimer; late StreamSubscription _subscription; - getFakeTimerModel()async { - TimerModel fakeTimer = await Utils.genFakeTimerModel(); - return fakeTimer; + getFakeTimerModel() async { + TimerModel fakeTimer = await Utils.genFakeTimerModel(); + return fakeTimer; } + @override void onInit() async { super.onInit(); @@ -23,7 +26,7 @@ class TimerRingController extends GetxController { // Preventing app from being minimized! _subscription = FGBGEvents.stream.listen((event) { if (event == FGBGType.background) { - timerChannel.invokeMethod('bringAppToForeground'); + bringAppToForegroundForTest(); } }); vibrationTimer = @@ -32,7 +35,17 @@ class TimerRingController extends GetxController { }); AudioUtils.playTimer(alarmRecord: await getFakeTimerModel().value); - await timerChannel.invokeMethod('cancelTimer'); + await clearTimerNotificationForTest(); + } + + @visibleForTesting + Future bringAppToForegroundForTest() async { + await alarmChannel.invokeMethod('bringAppToForeground'); + } + + @visibleForTesting + Future clearTimerNotificationForTest() async { + await timerChannel.invokeMethod('clearTimerNotif'); } @override diff --git a/test/app/modules/timer/timer_channel_contract_test.dart b/test/app/modules/timer/timer_channel_contract_test.dart new file mode 100644 index 000000000..fd1b9e766 --- /dev/null +++ b/test/app/modules/timer/timer_channel_contract_test.dart @@ -0,0 +1,80 @@ +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:ultimate_alarm_clock/app/modules/timer/controllers/timer_controller.dart'; +import 'package:ultimate_alarm_clock/app/modules/timerRing/controllers/timer_ring_controller.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const timerChannel = MethodChannel('timer'); + const alarmChannel = MethodChannel('ulticlock'); + + setUp(() { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(timerChannel, (_) async => null); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(alarmChannel, (_) async => null); + }); + + tearDown(() { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(timerChannel, null); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(alarmChannel, null); + }); + + test( + 'TimerController cancelTimer uses the implemented timer notification clear method', + () async { + MethodCall? capturedCall; + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(timerChannel, (call) async { + capturedCall = call; + return null; + }); + + final controller = TimerController(); + await controller.cancelTimer(); + + expect(capturedCall?.method, 'clearTimerNotif'); + }); + + test('TimerRingController foreground recovery uses the alarm channel', + () async { + MethodCall? timerCall; + MethodCall? alarmCall; + + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(timerChannel, (call) async { + timerCall = call; + return null; + }); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(alarmChannel, (call) async { + alarmCall = call; + return null; + }); + + final controller = TimerRingController(); + await controller.bringAppToForegroundForTest(); + + expect(timerCall, isNull); + expect(alarmCall?.method, 'bringAppToForeground'); + }); + + test( + 'TimerRingController clears timer notifications through the timer channel', + () async { + MethodCall? timerCall; + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(timerChannel, (call) async { + timerCall = call; + return null; + }); + + final controller = TimerRingController(); + await controller.clearTimerNotificationForTest(); + + expect(timerCall?.method, 'clearTimerNotif'); + }); +}