@@ -4,6 +4,7 @@ import 'package:flutter/foundation.dart';
44import 'package:flutter_riverpod/flutter_riverpod.dart' ;
55import 'package:freezed_annotation/freezed_annotation.dart' ;
66import 'package:lichess_mobile/src/model/clock/chess_clock.dart' ;
7+ import 'package:lichess_mobile/src/model/clock/clock_tool_preferences.dart' ;
78import 'package:lichess_mobile/src/model/common/service/sound_service.dart' ;
89import 'package:lichess_mobile/src/model/common/time_increment.dart' ;
910
@@ -32,26 +33,36 @@ class ClockToolController extends Notifier<ClockState> {
3233 ClockSide .top: false ,
3334 ClockSide .bottom: false ,
3435 };
35- late Duration _emergencyThreshold;
36+ final Map <ClockSide , Duration > _emergencyThresholds = {
37+ ClockSide .top: Duration .zero,
38+ ClockSide .bottom: Duration .zero,
39+ };
3640 DateTime ? _delayStartedAt;
3741 Duration ? _delayDuration;
3842 Duration ? _pausedDelayRemaining;
3943 Duration ? _activeTurnStartedWithTime;
4044
4145 @override
4246 ClockState build () {
43- const time = Duration (minutes: 10 );
44- const increment = Duration .zero;
45- _emergencyThreshold = _calculateEmergencyThreshold (time);
46- const options = ClockOptions (
47+ // using read is good enough as config change updates in-memory state which re-renders the ui
48+ // and prefs are also saved
49+ final topTimeIncrement = ref.read (clockToolPreferencesProvider).topTimeIncrement;
50+ final topTime = Duration (seconds: topTimeIncrement.time);
51+ final topIncrement = Duration (seconds: topTimeIncrement.increment);
52+ final bottomTimeIncrement = ref.read (clockToolPreferencesProvider).bottomTimeIncrement;
53+ final bottomTime = Duration (seconds: bottomTimeIncrement.time);
54+ final bottomIncrement = Duration (seconds: bottomTimeIncrement.increment);
55+ _emergencyThresholds[ClockSide .top] = _calculateEmergencyThreshold (topTime);
56+ _emergencyThresholds[ClockSide .bottom] = _calculateEmergencyThreshold (bottomTime);
57+ final options = ClockOptions (
4758 type: ClockTimeControlType .increment,
48- topTime: time ,
49- bottomTime: time ,
50- topIncrement: increment ,
51- bottomIncrement: increment ,
59+ topTime: topTime ,
60+ bottomTime: bottomTime ,
61+ topIncrement: topIncrement ,
62+ bottomIncrement: bottomIncrement ,
5263 );
5364
54- _clock = ChessClock (blackTime: time , whiteTime: time , onFlag: _onFlagged);
65+ _clock = ChessClock (blackTime: topTime , whiteTime: bottomTime , onFlag: _onFlagged);
5566
5667 // Add listeners for both clocks
5768 _clock.whiteTime.addListener (onClockEmergency);
@@ -84,7 +95,7 @@ class ClockToolController extends Notifier<ClockState> {
8495 final activeSideTime = activeSide == ClockSide .top
8596 ? _clock.blackTime.value
8697 : _clock.whiteTime.value;
87- if (activeSideTime <= _emergencyThreshold ) {
98+ if (activeSideTime <= _emergencyThresholds[activeSide] ! ) {
8899 ref.read (soundServiceProvider).play (Sound .lowTime);
89100 _hasPlayedLowTimeSound[activeSide] = true ;
90101 }
@@ -113,20 +124,11 @@ class ClockToolController extends Notifier<ClockState> {
113124 _startActiveSide (playerType.opposite);
114125 }
115126
116- void updateDuration (ClockSide playerType, Duration duration) {
117- if (state.flagged != null || state.paused) {
118- return ;
119- }
120-
121- _clock.setTimes (
122- whiteTime: playerType == ClockSide .bottom ? duration + state.options.topIncrement : null ,
123- blackTime: playerType == ClockSide .top ? duration + state.options.bottomIncrement : null ,
124- );
125- }
126-
127127 void updateOptions (TimeIncrement timeIncrement) {
128128 final options = ClockOptions .fromTimeIncrement (timeIncrement, type: state.options.type);
129- _emergencyThreshold = _calculateEmergencyThreshold (Duration (seconds: timeIncrement.time));
129+ final threshold = _calculateEmergencyThreshold (Duration (seconds: timeIncrement.time));
130+ _emergencyThresholds[ClockSide .top] = threshold;
131+ _emergencyThresholds[ClockSide .bottom] = threshold;
130132 _hasPlayedLowTimeSound[ClockSide .top] = false ;
131133 _hasPlayedLowTimeSound[ClockSide .bottom] = false ;
132134 _clock.setTimes (blackTime: options.topTime, whiteTime: options.bottomTime);
@@ -135,6 +137,7 @@ class ClockToolController extends Notifier<ClockState> {
135137 topTime: _clock.blackTime,
136138 bottomTime: _clock.whiteTime,
137139 );
140+ ref.read (clockToolPreferencesProvider.notifier).setTimeIncrement (timeIncrement);
138141 }
139142
140143 void updateOptionsCustom (TimeIncrement clock, ClockSide player) {
@@ -151,6 +154,8 @@ class ClockToolController extends Notifier<ClockState> {
151154 ? Duration (seconds: clock.increment)
152155 : state.options.bottomIncrement,
153156 );
157+ _emergencyThresholds[player] = _calculateEmergencyThreshold (Duration (seconds: clock.time));
158+ _hasPlayedLowTimeSound[player] = false ;
154159 _clock.setTimes (blackTime: options.topTime, whiteTime: options.bottomTime);
155160 state = ClockState (
156161 options: options,
@@ -159,6 +164,12 @@ class ClockToolController extends Notifier<ClockState> {
159164 activeSide: state.activeSide,
160165 clockOrientation: state.clockOrientation,
161166 );
167+
168+ if (player == ClockSide .top) {
169+ ref.read (clockToolPreferencesProvider.notifier).setTopTimeIncrement (clock);
170+ } else {
171+ ref.read (clockToolPreferencesProvider.notifier).setBottomTimeIncrement (clock);
172+ }
162173 }
163174
164175 void updateClockType (ClockTimeControlType type) {
@@ -199,14 +210,10 @@ class ClockToolController extends Notifier<ClockState> {
199210 final active = state.activeSide;
200211 // If the active side started at zero, only resume ticking after that side
201212 // has completed at least one move; otherwise behave normally.
202- final Duration initialOfActive = active == ClockSide .top
203- ? state.options.topTime
204- : state.options.bottomTime;
205- final bool hasActiveMoved = active == ClockSide .top
206- ? state.topMoves > 0
207- : state.bottomMoves > 0 ;
208-
209- if (active != null && (initialOfActive.inMilliseconds != 0 || hasActiveMoved)) {
213+ final bool hasActiveMoved = active != null && state.getMovesCount (active) > 0 ;
214+
215+ if (active != null &&
216+ (state.options.getStartTime (active).inMilliseconds != 0 || hasActiveMoved)) {
210217 final delay = _pausedDelayRemaining;
211218 _markDelay (delay);
212219 _clock.start (delay: delay);
@@ -223,13 +230,8 @@ class ClockToolController extends Notifier<ClockState> {
223230 // Start the countdown only if either this is not a zero-start clock
224231 // or the active side has already made at least one move.
225232 // This makes 0+increment modes usable.
226- final Duration initialOfActive = activeSide == ClockSide .top
227- ? state.options.topTime
228- : state.options.bottomTime;
229- final bool hasActiveMoved = activeSide == ClockSide .top
230- ? state.topMoves > 0
231- : state.bottomMoves > 0 ;
232- if (initialOfActive.inMilliseconds != 0 || hasActiveMoved) {
233+ final bool hasActiveMoved = state.getMovesCount (activeSide) > 0 ;
234+ if (state.options.getStartTime (activeSide).inMilliseconds != 0 || hasActiveMoved) {
233235 final delay = _delayFor (activeSide);
234236 _markDelay (delay);
235237 _activeTurnStartedWithTime = state.getDuration (activeSide).value;
@@ -334,6 +336,10 @@ sealed class ClockOptions with _$ClockOptions {
334336 bool hasIncrement (ClockSide playerType) {
335337 return getIncrement (playerType) > 0 ;
336338 }
339+
340+ Duration getStartTime (ClockSide playerType) {
341+ return playerType == ClockSide .top ? topTime : bottomTime;
342+ }
337343}
338344
339345@freezed
0 commit comments