From 0979c26940cfc3b8734a79b6753b81a478c7072c Mon Sep 17 00:00:00 2001 From: tom-anders <13141438+tom-anders@users.noreply.github.com> Date: Thu, 27 Jun 2024 15:27:47 +0200 Subject: [PATCH] feat: support disabling clock emergency sound Closes #785 --- lib/src/model/account/account_preferences.dart | 11 +++++++++++ lib/src/model/account/account_repository.dart | 1 + lib/src/view/game/game_body.dart | 7 +++++++ .../view/settings/account_preferences_screen.dart | 14 ++++++++++++++ lib/src/widgets/countdown_clock.dart | 8 +++++++- 5 files changed, 40 insertions(+), 1 deletion(-) diff --git a/lib/src/model/account/account_preferences.dart b/lib/src/model/account/account_preferences.dart index 9dbece200b..da31f11175 100644 --- a/lib/src/model/account/account_preferences.dart +++ b/lib/src/model/account/account_preferences.dart @@ -22,6 +22,7 @@ typedef AccountPrefState = ({ SubmitMove submitMove, // clock Moretime moretime, + BooleanPref clockSound, // privacy BooleanPref follow, }); @@ -34,6 +35,13 @@ final showRatingsPrefProvider = FutureProvider((ref) async { ); }); +final clockSoundProvider = FutureProvider((ref) async { + return ref.watch( + accountPreferencesProvider + .selectAsync((state) => state?.clockSound.value ?? true), + ); +}); + final defaultAccountPreferences = ( zenMode: Zen.no, showRatings: const BooleanPref(true), @@ -42,6 +50,7 @@ final defaultAccountPreferences = ( autoThreefold: AutoThreefold.always, takeback: Takeback.always, moretime: Moretime.always, + clockSound: const BooleanPref(true), confirmResign: const BooleanPref(true), submitMove: SubmitMove({ SubmitMoveChoice.correspondence, @@ -84,6 +93,8 @@ class AccountPreferences extends _$AccountPreferences { Future setAutoThreefold(AutoThreefold value) => _setPref('autoThreefold', value); Future setMoretime(Moretime value) => _setPref('moretime', value); + Future setClockSound(BooleanPref value) => + _setPref('clockSound', value); Future setConfirmResign(BooleanPref value) => _setPref('confirmResign', value); Future setSubmitMove(SubmitMove value) => _setPref('submitMove', value); diff --git a/lib/src/model/account/account_repository.dart b/lib/src/model/account/account_repository.dart index e85bc03221..89eca1080f 100644 --- a/lib/src/model/account/account_repository.dart +++ b/lib/src/model/account/account_repository.dart @@ -153,6 +153,7 @@ AccountPrefState _accountPreferencesFromPick(RequiredPick pick) { moretime: Moretime.fromInt( pick('moretime').asIntOrThrow(), ), + clockSound: BooleanPref(pick('clockSound').asBoolOrThrow()), confirmResign: BooleanPref.fromInt( pick('confirmResign').asIntOrThrow(), ), diff --git a/lib/src/view/game/game_body.dart b/lib/src/view/game/game_body.dart index 37e9aae80a..f704d6de57 100644 --- a/lib/src/view/game/game_body.dart +++ b/lib/src/view/game/game_body.dart @@ -8,6 +8,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:lichess_mobile/src/constants.dart'; +import 'package:lichess_mobile/src/model/account/account_preferences.dart'; import 'package:lichess_mobile/src/model/account/account_repository.dart'; import 'package:lichess_mobile/src/model/common/id.dart'; import 'package:lichess_mobile/src/model/common/speed.dart'; @@ -104,6 +105,10 @@ class GameBody extends ConsumerWidget { ); final boardPreferences = ref.watch(boardPreferencesProvider); + final emergencySoundEnabled = ref.watch(clockSoundProvider).maybeWhen( + data: (clockSound) => clockSound, + orElse: () => true, + ); final blindfoldMode = ref.watch( gamePreferencesProvider.select( @@ -152,6 +157,7 @@ class GameBody extends ConsumerWidget { emergencyThreshold: youAre == Side.black ? gameState.game.meta.clock?.emergency : null, + emergencySoundEnabled: emergencySoundEnabled, onFlag: () => ref.read(ctrlProvider.notifier).onFlag(), ) : gameState.game.correspondenceClock != null @@ -192,6 +198,7 @@ class GameBody extends ConsumerWidget { emergencyThreshold: youAre == Side.white ? gameState.game.meta.clock?.emergency : null, + emergencySoundEnabled: emergencySoundEnabled, onFlag: () => ref.read(ctrlProvider.notifier).onFlag(), ) : gameState.game.correspondenceClock != null diff --git a/lib/src/view/settings/account_preferences_screen.dart b/lib/src/view/settings/account_preferences_screen.dart index 8bfe4f2dd4..fa5ede5cfb 100644 --- a/lib/src/view/settings/account_preferences_screen.dart +++ b/lib/src/view/settings/account_preferences_screen.dart @@ -322,6 +322,20 @@ class _AccountPreferencesScreenState } }, ), + SwitchSettingTile( + title: + Text(context.l10n.preferencesSoundWhenTimeGetsCritical), + value: data.clockSound.value, + onChanged: isLoading + ? null + : (value) { + _setPref( + () => ref + .read(accountPreferencesProvider.notifier) + .setClockSound(BooleanPref(value)), + ); + }, + ), ], ), ListSection( diff --git a/lib/src/widgets/countdown_clock.dart b/lib/src/widgets/countdown_clock.dart index 0b00b8ffc5..acb2a81948 100644 --- a/lib/src/widgets/countdown_clock.dart +++ b/lib/src/widgets/countdown_clock.dart @@ -17,8 +17,11 @@ class CountdownClock extends ConsumerStatefulWidget { /// If [timeLeft] is less than [emergencyThreshold], the clock will change /// its background color to [ClockStyle.emergencyBackgroundColor] activeBackgroundColor + /// If [emergencySoundEnabled] is `true`, the clock will also play a sound. final Duration? emergencyThreshold; + final bool emergencySoundEnabled; + /// If [active] is `true`, the clock starts counting down. final bool active; @@ -38,6 +41,7 @@ class CountdownClock extends ConsumerStatefulWidget { required this.duration, required this.active, this.emergencyThreshold, + this.emergencySoundEnabled = true, this.onFlag, this.onStop, this.lightColorStyle, @@ -93,7 +97,9 @@ class _CountdownClockState extends ConsumerState { (_nextEmergency == null || _nextEmergency!.isBefore(DateTime.now()))) { _shouldPlayEmergencyFeedback = false; _nextEmergency = DateTime.now().add(_emergencyDelay); - ref.read(soundServiceProvider).play(Sound.lowTime); + if (widget.emergencySoundEnabled) { + ref.read(soundServiceProvider).play(Sound.lowTime); + } HapticFeedback.heavyImpact(); } else if (widget.emergencyThreshold != null && timeLeft > widget.emergencyThreshold! * 1.5) {