Skip to content

Commit

Permalink
Fix broadcast clock update issues
Browse files Browse the repository at this point in the history
  • Loading branch information
veloce committed Dec 12, 2024
1 parent 0b8c1d9 commit 9a6a400
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 19 deletions.
7 changes: 6 additions & 1 deletion lib/src/model/broadcast/broadcast_game_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ class BroadcastGameController extends _$BroadcastGameController

// check provider is still mounted
if (key == _key) {
final curState = state.requireValue;
final wasOnLivePath = curState.broadcastLivePath == curState.currentPath;
final game = PgnGame.parsePgn(pgn);
final pgnHeaders = IMap(game.headers);
final rootComments =
Expand All @@ -167,14 +169,17 @@ class BroadcastGameController extends _$BroadcastGameController

_root = newRoot;

final newCurrentPath =
wasOnLivePath ? broadcastPath : curState.currentPath;
state = AsyncData(
state.requireValue.copyWith(
currentPath: newCurrentPath,
pgnHeaders: pgnHeaders,
pgnRootComments: rootComments,
broadcastPath: broadcastPath,
root: _root.view,
lastMove: lastMove,
clocks: _getClocks(state.requireValue.currentPath),
clocks: _getClocks(newCurrentPath),
),
);
}
Expand Down
28 changes: 23 additions & 5 deletions lib/src/model/broadcast/broadcast_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -177,29 +177,47 @@ MapEntry<BroadcastGameId, BroadcastGame> gameFromPick(
/// The amount of time that the player whose turn it is has been thinking since his last move
final thinkTime =
pick('thinkTime').asDurationFromSecondsOrNull() ?? Duration.zero;
final fen =
pick('fen').asStringOrNull() ?? Variant.standard.initialPosition.fen;
final playingSide = Setup.parseFen(fen).turn;

return MapEntry(
pick('id').asBroadcastGameIdOrThrow(),
BroadcastGame(
id: pick('id').asBroadcastGameIdOrThrow(),
players: IMap({
Side.white: _playerFromPick(pick('players', 0).required()),
Side.black: _playerFromPick(pick('players', 1).required()),
Side.white: _playerFromPick(
pick('players', 0).required(),
isPlaying: playingSide == Side.white,
thinkingTime: thinkTime,
),
Side.black: _playerFromPick(
pick('players', 1).required(),
isPlaying: playingSide == Side.black,
thinkingTime: thinkTime,
),
}),
fen: pick('fen').asStringOrNull() ?? Variant.standard.initialPosition.fen,
lastMove: pick('lastMove').asUciMoveOrNull(),
status: status,
updatedClockAt: DateTime.now().subtract(thinkTime),
updatedClockAt: DateTime.now(),
),
);
}

BroadcastPlayer _playerFromPick(RequiredPick pick) {
BroadcastPlayer _playerFromPick(
RequiredPick pick, {
required bool isPlaying,
required Duration thinkingTime,
}) {
final clock = pick('clock').asDurationFromCentiSecondsOrNull();
final updatedClock =
clock != null && isPlaying ? clock - thinkingTime : clock;
return BroadcastPlayer(
name: pick('name').asStringOrThrow(),
title: pick('title').asStringOrNull(),
rating: pick('rating').asIntOrNull(),
clock: pick('clock').asDurationFromCentiSecondsOrNull(),
clock: updatedClock,
federation: pick('fed').asStringOrNull(),
fideId: pick('fideId').asFideIdOrNull(),
);
Expand Down
1 change: 1 addition & 0 deletions lib/src/model/broadcast/broadcast_round_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ class BroadcastRoundController extends _$BroadcastRoundController {
),
},
),
updatedClockAt: DateTime.now(),
),
),
),
Expand Down
30 changes: 17 additions & 13 deletions lib/src/view/broadcast/broadcast_game_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -369,23 +369,28 @@ class _PlayerWidget extends ConsumerWidget {
final broadcastGameState = ref
.watch(broadcastGameControllerProvider(roundId, gameId))
.requireValue;
final clocks = broadcastGameState.clocks;
// TODO
// we'll probably want to remove this and get the game state from a single controller
// this won't work with deep links for instance
final game = ref.watch(
broadcastRoundControllerProvider(roundId)
.select((round) => round.requireValue.games[gameId]!),
);
final isCursorOnLiveMove =
broadcastGameState.currentPath == broadcastGameState.broadcastLivePath;
final sideToMove = broadcastGameState.position.turn;
final side = switch (widgetPosition) {
_PlayerWidgetPosition.bottom => broadcastGameState.pov,
_PlayerWidgetPosition.top => broadcastGameState.pov.opposite,
};
final clock = (sideToMove == side) ? clocks?.parentClock : clocks?.clock;

final game = ref.watch(
broadcastRoundControllerProvider(roundId)
.select((round) => round.requireValue.games[gameId]!),
);
final player = game.players[side]!;
final liveClock = isCursorOnLiveMove ? player.clock : null;
final gameStatus = game.status;

final pastClocks = broadcastGameState.clocks;
final pastClock =
(sideToMove == side) ? pastClocks?.parentClock : pastClocks?.clock;

return Container(
color: Theme.of(context).platform == TargetPlatform.iOS
? Styles.cupertinoCardColor.resolveFrom(context)
Expand Down Expand Up @@ -418,7 +423,7 @@ class _PlayerWidget extends ConsumerWidget {
const TextStyle().copyWith(fontWeight: FontWeight.bold),
),
),
if (clock != null)
if (liveClock != null || pastClock != null)
Container(
height: kAnalysisBoardHeaderOrFooterHeight,
color: (side == sideToMove)
Expand All @@ -429,21 +434,20 @@ class _PlayerWidget extends ConsumerWidget {
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 6.0),
child: Center(
child: isCursorOnLiveMove
child: liveClock != null
? CountdownClockBuilder(
timeLeft: clock,
timeLeft: liveClock,
active: side == sideToMove,
builder: (context, timeLeft) => _Clock(
timeLeft: timeLeft,
isSideToMove: side == sideToMove,
isLive: true,
),
tickInterval: const Duration(seconds: 1),
clockUpdatedAt:
side == sideToMove ? game.updatedClockAt : null,
clockUpdatedAt: game.updatedClockAt,
)
: _Clock(
timeLeft: clock,
timeLeft: pastClock!,
isSideToMove: side == sideToMove,
isLive: false,
),
Expand Down

0 comments on commit 9a6a400

Please sign in to comment.