784 lines
23 KiB
Dart
784 lines
23 KiB
Dart
const int watchBridgeSchemaVersion = 5;
|
|
|
|
enum WatchCommandType {
|
|
startCurrentExercise,
|
|
pauseSession,
|
|
resumeSession,
|
|
startPreparedTimedStep,
|
|
completeCurrentStep,
|
|
skipCurrentStep,
|
|
skipCurrentPassage,
|
|
finishCurrentSet,
|
|
skipCurrentSet,
|
|
skipCurrentRest,
|
|
incrementScore,
|
|
decrementScore,
|
|
}
|
|
|
|
enum WatchCommandAck {
|
|
accepted,
|
|
acceptedNoOp,
|
|
rejectedStaleRevision,
|
|
rejectedNotApplicable,
|
|
rejectedNoActiveSession,
|
|
rejectedSessionMismatch,
|
|
rejectedPhoneBusy,
|
|
}
|
|
|
|
enum WatchSessionPhase {
|
|
noActiveSession,
|
|
ready,
|
|
running,
|
|
paused,
|
|
nextTimerReady,
|
|
restRunning,
|
|
restPaused,
|
|
betweenSetsReady,
|
|
}
|
|
|
|
enum WatchPrimaryAction {
|
|
none,
|
|
startCurrentExercise,
|
|
pauseSession,
|
|
resumeSession,
|
|
startPreparedTimedStep,
|
|
skipCurrentRest,
|
|
}
|
|
|
|
enum WatchSecondaryAction {
|
|
skipCurrentStep,
|
|
skipCurrentPassage,
|
|
finishCurrentSet,
|
|
skipCurrentSet,
|
|
skipCurrentRest,
|
|
}
|
|
|
|
enum WatchTimerKind { rest, step, scoreStopwatch, setTimer }
|
|
|
|
enum WatchTimerDisplayMode { countdown, elapsed }
|
|
|
|
enum WatchTimerRunState { stopped, running, paused }
|
|
|
|
enum WatchManualScoreScope { series, step }
|
|
|
|
enum WatchStepType { time, reps }
|
|
|
|
final class WatchCommandEnvelope {
|
|
const WatchCommandEnvelope({
|
|
this.schemaVersion = watchBridgeSchemaVersion,
|
|
required this.commandId,
|
|
required this.type,
|
|
required this.sessionId,
|
|
required this.expectedRevision,
|
|
required this.sentAtEpochMs,
|
|
});
|
|
|
|
factory WatchCommandEnvelope.fromJson(Map<String, Object?> json) {
|
|
return WatchCommandEnvelope(
|
|
schemaVersion: _intFromJson(
|
|
json['schemaVersion'],
|
|
watchBridgeSchemaVersion,
|
|
),
|
|
commandId: _stringFromJson(json['commandId']),
|
|
type: _enumFromJson(
|
|
json['type'],
|
|
WatchCommandType.values,
|
|
WatchCommandType.startCurrentExercise,
|
|
),
|
|
sessionId: _stringFromJson(json['sessionId']),
|
|
expectedRevision: _intFromJson(json['expectedRevision'], 0),
|
|
sentAtEpochMs: _intFromJson(json['sentAtEpochMs'], 0),
|
|
);
|
|
}
|
|
|
|
final int schemaVersion;
|
|
final String commandId;
|
|
final WatchCommandType type;
|
|
final String sessionId;
|
|
final int expectedRevision;
|
|
final int sentAtEpochMs;
|
|
|
|
Map<String, Object?> toJson() {
|
|
return {
|
|
'schemaVersion': schemaVersion,
|
|
'commandId': commandId,
|
|
'type': type.name,
|
|
'sessionId': sessionId,
|
|
'expectedRevision': expectedRevision,
|
|
'sentAtEpochMs': sentAtEpochMs,
|
|
};
|
|
}
|
|
|
|
@override
|
|
bool operator ==(Object other) {
|
|
return identical(this, other) ||
|
|
other is WatchCommandEnvelope &&
|
|
schemaVersion == other.schemaVersion &&
|
|
commandId == other.commandId &&
|
|
type == other.type &&
|
|
sessionId == other.sessionId &&
|
|
expectedRevision == other.expectedRevision &&
|
|
sentAtEpochMs == other.sentAtEpochMs;
|
|
}
|
|
|
|
@override
|
|
int get hashCode {
|
|
return Object.hash(
|
|
schemaVersion,
|
|
commandId,
|
|
type,
|
|
sessionId,
|
|
expectedRevision,
|
|
sentAtEpochMs,
|
|
);
|
|
}
|
|
}
|
|
|
|
final class WatchSessionProjection {
|
|
const WatchSessionProjection({
|
|
this.schemaVersion = watchBridgeSchemaVersion,
|
|
required this.deviceSessionId,
|
|
required this.revision,
|
|
required this.projectedAtEpochMs,
|
|
this.expiresAtEpochMs = 0,
|
|
required this.phase,
|
|
required this.phoneReachable,
|
|
required this.seriesIndex,
|
|
required this.seriesTotal,
|
|
required this.exerciseName,
|
|
this.programIndex,
|
|
this.exerciseIndex,
|
|
this.setIndex,
|
|
this.passageIndex,
|
|
this.passageTotal,
|
|
this.stepIndex,
|
|
this.stepTotal,
|
|
this.stepName,
|
|
this.stepType,
|
|
this.stepTargetValue,
|
|
this.dominantTimer,
|
|
this.secondaryTimers = const [],
|
|
required this.primaryAction,
|
|
this.secondaryActions = const [],
|
|
this.nextExerciseName,
|
|
this.statusLabel,
|
|
this.hasManualScore = false,
|
|
this.currentManualScoreValue,
|
|
this.canDecrementScore = false,
|
|
this.manualScoreTargetValue,
|
|
this.manualScoreTargetLabel,
|
|
this.manualScoreRepsTargetValue,
|
|
this.manualScoreScope,
|
|
});
|
|
|
|
factory WatchSessionProjection.fromJson(Map<String, Object?> json) {
|
|
return WatchSessionProjection(
|
|
schemaVersion: _intFromJson(
|
|
json['schemaVersion'],
|
|
watchBridgeSchemaVersion,
|
|
),
|
|
deviceSessionId: _stringFromJson(json['deviceSessionId']),
|
|
revision: _intFromJson(json['revision'], 0),
|
|
projectedAtEpochMs: _intFromJson(json['projectedAtEpochMs'], 0),
|
|
expiresAtEpochMs: _intFromJson(json['expiresAtEpochMs'], 0),
|
|
phase: _enumFromJson(
|
|
json['phase'],
|
|
WatchSessionPhase.values,
|
|
WatchSessionPhase.noActiveSession,
|
|
),
|
|
phoneReachable: _boolFromJson(json['phoneReachable'], false),
|
|
seriesIndex: _intFromJson(json['seriesIndex'], 0),
|
|
seriesTotal: _intFromJson(json['seriesTotal'], 0),
|
|
exerciseName: _stringFromJson(json['exerciseName']),
|
|
programIndex: _nullableIntFromJson(json['programIndex']),
|
|
exerciseIndex: _nullableIntFromJson(json['exerciseIndex']),
|
|
setIndex: _nullableIntFromJson(json['setIndex']),
|
|
passageIndex: _nullableIntFromJson(json['passageIndex']),
|
|
passageTotal: _nullableIntFromJson(json['passageTotal']),
|
|
stepIndex: _nullableIntFromJson(json['stepIndex']),
|
|
stepTotal: _nullableIntFromJson(json['stepTotal']),
|
|
stepName: _nullableStringFromJson(json['stepName']),
|
|
stepType: _nullableEnumFromJson(json['stepType'], WatchStepType.values),
|
|
stepTargetValue: _nullableIntFromJson(json['stepTargetValue']),
|
|
dominantTimer: _timerFromJson(json['dominantTimer']),
|
|
secondaryTimers: _timerListFromJson(json['secondaryTimers']),
|
|
primaryAction: _enumFromJson(
|
|
json['primaryAction'],
|
|
WatchPrimaryAction.values,
|
|
WatchPrimaryAction.none,
|
|
),
|
|
secondaryActions: _enumListFromJson(
|
|
json['secondaryActions'],
|
|
WatchSecondaryAction.values,
|
|
),
|
|
nextExerciseName: _nullableStringFromJson(json['nextExerciseName']),
|
|
statusLabel: _nullableStringFromJson(json['statusLabel']),
|
|
hasManualScore: _boolFromJson(json['hasManualScore'], false),
|
|
currentManualScoreValue: _nullableDoubleFromJson(
|
|
json['currentManualScoreValue'],
|
|
),
|
|
canDecrementScore: _boolFromJson(json['canDecrementScore'], false),
|
|
manualScoreTargetValue: _nullableDoubleFromJson(
|
|
json['manualScoreTargetValue'],
|
|
),
|
|
manualScoreTargetLabel: _nullableStringFromJson(
|
|
json['manualScoreTargetLabel'],
|
|
),
|
|
manualScoreRepsTargetValue: _nullableIntFromJson(
|
|
json['manualScoreRepsTargetValue'],
|
|
),
|
|
manualScoreScope: _nullableEnumFromJson(
|
|
json['manualScoreScope'],
|
|
WatchManualScoreScope.values,
|
|
),
|
|
);
|
|
}
|
|
|
|
final int schemaVersion;
|
|
final String deviceSessionId;
|
|
final int revision;
|
|
final int projectedAtEpochMs;
|
|
final int expiresAtEpochMs;
|
|
final WatchSessionPhase phase;
|
|
final bool phoneReachable;
|
|
final int seriesIndex;
|
|
final int seriesTotal;
|
|
final String exerciseName;
|
|
final int? programIndex;
|
|
final int? exerciseIndex;
|
|
final int? setIndex;
|
|
final int? passageIndex;
|
|
final int? passageTotal;
|
|
final int? stepIndex;
|
|
final int? stepTotal;
|
|
final String? stepName;
|
|
final WatchStepType? stepType;
|
|
final int? stepTargetValue;
|
|
final WatchTimerProjection? dominantTimer;
|
|
final List<WatchTimerProjection> secondaryTimers;
|
|
final WatchPrimaryAction primaryAction;
|
|
final List<WatchSecondaryAction> secondaryActions;
|
|
final String? nextExerciseName;
|
|
final String? statusLabel;
|
|
final bool hasManualScore;
|
|
final double? currentManualScoreValue;
|
|
final bool canDecrementScore;
|
|
final double? manualScoreTargetValue;
|
|
final String? manualScoreTargetLabel;
|
|
final int? manualScoreRepsTargetValue;
|
|
final WatchManualScoreScope? manualScoreScope;
|
|
|
|
Map<String, Object?> toJson() {
|
|
return {
|
|
'schemaVersion': schemaVersion,
|
|
'deviceSessionId': deviceSessionId,
|
|
'revision': revision,
|
|
'projectedAtEpochMs': projectedAtEpochMs,
|
|
'expiresAtEpochMs': expiresAtEpochMs,
|
|
'phase': phase.name,
|
|
'phoneReachable': phoneReachable,
|
|
'seriesIndex': seriesIndex,
|
|
'seriesTotal': seriesTotal,
|
|
'exerciseName': exerciseName,
|
|
'programIndex': programIndex,
|
|
'exerciseIndex': exerciseIndex,
|
|
'setIndex': setIndex,
|
|
'passageIndex': passageIndex,
|
|
'passageTotal': passageTotal,
|
|
'stepIndex': stepIndex,
|
|
'stepTotal': stepTotal,
|
|
'stepName': stepName,
|
|
'stepType': stepType?.name,
|
|
'stepTargetValue': stepTargetValue,
|
|
'dominantTimer': dominantTimer?.toJson(),
|
|
'secondaryTimers': secondaryTimers
|
|
.map((timer) => timer.toJson())
|
|
.toList(),
|
|
'primaryAction': primaryAction.name,
|
|
'secondaryActions': secondaryActions
|
|
.map((action) => action.name)
|
|
.toList(),
|
|
'nextExerciseName': nextExerciseName,
|
|
'statusLabel': statusLabel,
|
|
'hasManualScore': hasManualScore,
|
|
'currentManualScoreValue': currentManualScoreValue,
|
|
'canDecrementScore': canDecrementScore,
|
|
'manualScoreTargetValue': manualScoreTargetValue,
|
|
'manualScoreTargetLabel': manualScoreTargetLabel,
|
|
'manualScoreRepsTargetValue': manualScoreRepsTargetValue,
|
|
'manualScoreScope': manualScoreScope?.name,
|
|
};
|
|
}
|
|
|
|
@override
|
|
bool operator ==(Object other) {
|
|
return identical(this, other) ||
|
|
other is WatchSessionProjection &&
|
|
schemaVersion == other.schemaVersion &&
|
|
deviceSessionId == other.deviceSessionId &&
|
|
revision == other.revision &&
|
|
projectedAtEpochMs == other.projectedAtEpochMs &&
|
|
expiresAtEpochMs == other.expiresAtEpochMs &&
|
|
phase == other.phase &&
|
|
phoneReachable == other.phoneReachable &&
|
|
seriesIndex == other.seriesIndex &&
|
|
seriesTotal == other.seriesTotal &&
|
|
exerciseName == other.exerciseName &&
|
|
programIndex == other.programIndex &&
|
|
exerciseIndex == other.exerciseIndex &&
|
|
setIndex == other.setIndex &&
|
|
passageIndex == other.passageIndex &&
|
|
passageTotal == other.passageTotal &&
|
|
stepIndex == other.stepIndex &&
|
|
stepTotal == other.stepTotal &&
|
|
stepName == other.stepName &&
|
|
stepType == other.stepType &&
|
|
stepTargetValue == other.stepTargetValue &&
|
|
dominantTimer == other.dominantTimer &&
|
|
_listEquals(secondaryTimers, other.secondaryTimers) &&
|
|
primaryAction == other.primaryAction &&
|
|
_listEquals(secondaryActions, other.secondaryActions) &&
|
|
nextExerciseName == other.nextExerciseName &&
|
|
statusLabel == other.statusLabel &&
|
|
hasManualScore == other.hasManualScore &&
|
|
currentManualScoreValue == other.currentManualScoreValue &&
|
|
canDecrementScore == other.canDecrementScore &&
|
|
manualScoreTargetValue == other.manualScoreTargetValue &&
|
|
manualScoreTargetLabel == other.manualScoreTargetLabel &&
|
|
manualScoreRepsTargetValue == other.manualScoreRepsTargetValue &&
|
|
manualScoreScope == other.manualScoreScope;
|
|
}
|
|
|
|
@override
|
|
int get hashCode {
|
|
return Object.hashAll([
|
|
schemaVersion,
|
|
deviceSessionId,
|
|
revision,
|
|
projectedAtEpochMs,
|
|
expiresAtEpochMs,
|
|
phase,
|
|
phoneReachable,
|
|
seriesIndex,
|
|
seriesTotal,
|
|
exerciseName,
|
|
programIndex,
|
|
exerciseIndex,
|
|
setIndex,
|
|
passageIndex,
|
|
passageTotal,
|
|
stepIndex,
|
|
stepTotal,
|
|
stepName,
|
|
stepType,
|
|
stepTargetValue,
|
|
dominantTimer,
|
|
Object.hashAll(secondaryTimers),
|
|
primaryAction,
|
|
Object.hashAll(secondaryActions),
|
|
nextExerciseName,
|
|
statusLabel,
|
|
hasManualScore,
|
|
currentManualScoreValue,
|
|
canDecrementScore,
|
|
manualScoreTargetValue,
|
|
manualScoreTargetLabel,
|
|
manualScoreRepsTargetValue,
|
|
manualScoreScope,
|
|
]);
|
|
}
|
|
}
|
|
|
|
final class WatchSensorSummary {
|
|
const WatchSensorSummary({
|
|
this.schemaVersion = watchBridgeSchemaVersion,
|
|
required this.sessionId,
|
|
required this.sampleCount,
|
|
this.minHeartRateBpm,
|
|
this.averageHeartRateBpm,
|
|
this.maxHeartRateBpm,
|
|
this.totalDistanceMeters,
|
|
this.totalCaloriesKcal,
|
|
});
|
|
|
|
factory WatchSensorSummary.fromJson(Map<String, Object?> json) {
|
|
return WatchSensorSummary(
|
|
schemaVersion: _intFromJson(
|
|
json['schemaVersion'],
|
|
watchBridgeSchemaVersion,
|
|
),
|
|
sessionId: _stringFromJson(json['sessionId']),
|
|
sampleCount: _intFromJson(json['sampleCount'], 0),
|
|
minHeartRateBpm: _nullableIntFromJson(json['minHeartRateBpm']),
|
|
averageHeartRateBpm: _nullableDoubleFromJson(json['averageHeartRateBpm']),
|
|
maxHeartRateBpm: _nullableIntFromJson(json['maxHeartRateBpm']),
|
|
totalDistanceMeters: _nullableDoubleFromJson(json['totalDistanceMeters']),
|
|
totalCaloriesKcal: _nullableDoubleFromJson(json['totalCaloriesKcal']),
|
|
);
|
|
}
|
|
|
|
final int schemaVersion;
|
|
final String sessionId;
|
|
final int sampleCount;
|
|
final int? minHeartRateBpm;
|
|
final double? averageHeartRateBpm;
|
|
final int? maxHeartRateBpm;
|
|
final double? totalDistanceMeters;
|
|
final double? totalCaloriesKcal;
|
|
|
|
Map<String, Object?> toJson() {
|
|
return {
|
|
'schemaVersion': schemaVersion,
|
|
'sessionId': sessionId,
|
|
'sampleCount': sampleCount,
|
|
'minHeartRateBpm': minHeartRateBpm,
|
|
'averageHeartRateBpm': averageHeartRateBpm,
|
|
'maxHeartRateBpm': maxHeartRateBpm,
|
|
'totalDistanceMeters': totalDistanceMeters,
|
|
'totalCaloriesKcal': totalCaloriesKcal,
|
|
};
|
|
}
|
|
|
|
@override
|
|
bool operator ==(Object other) {
|
|
return identical(this, other) ||
|
|
other is WatchSensorSummary &&
|
|
schemaVersion == other.schemaVersion &&
|
|
sessionId == other.sessionId &&
|
|
sampleCount == other.sampleCount &&
|
|
minHeartRateBpm == other.minHeartRateBpm &&
|
|
averageHeartRateBpm == other.averageHeartRateBpm &&
|
|
maxHeartRateBpm == other.maxHeartRateBpm &&
|
|
totalDistanceMeters == other.totalDistanceMeters &&
|
|
totalCaloriesKcal == other.totalCaloriesKcal;
|
|
}
|
|
|
|
@override
|
|
int get hashCode {
|
|
return Object.hash(
|
|
schemaVersion,
|
|
sessionId,
|
|
sampleCount,
|
|
minHeartRateBpm,
|
|
averageHeartRateBpm,
|
|
maxHeartRateBpm,
|
|
totalDistanceMeters,
|
|
totalCaloriesKcal,
|
|
);
|
|
}
|
|
}
|
|
|
|
final class WatchSensorSample {
|
|
const WatchSensorSample({
|
|
this.schemaVersion = watchBridgeSchemaVersion,
|
|
this.sampleId,
|
|
required this.sessionId,
|
|
int? capturedAtEpochMs,
|
|
int? recordedAtEpochMs,
|
|
this.programIndex,
|
|
this.exerciseIndex,
|
|
this.setIndex,
|
|
this.passageIndex,
|
|
this.stepIndex,
|
|
this.programSnapshotId,
|
|
this.exerciseSnapshotId,
|
|
this.stepSnapshotId,
|
|
this.heartRateBpm,
|
|
this.distanceMeters,
|
|
this.caloriesKcal,
|
|
}) : capturedAtEpochMs = capturedAtEpochMs ?? recordedAtEpochMs ?? 0;
|
|
|
|
factory WatchSensorSample.fromJson(Map<String, Object?> json) {
|
|
return WatchSensorSample(
|
|
schemaVersion: _intFromJson(
|
|
json['schemaVersion'],
|
|
watchBridgeSchemaVersion,
|
|
),
|
|
sampleId: _nullableStringFromJson(json['sampleId']),
|
|
sessionId: _stringFromJson(json['sessionId']),
|
|
capturedAtEpochMs: _intFromJson(
|
|
json['capturedAtEpochMs'],
|
|
_intFromJson(json['recordedAtEpochMs'], 0),
|
|
),
|
|
programIndex: _nullableIntFromJson(json['programIndex']),
|
|
exerciseIndex: _nullableIntFromJson(json['exerciseIndex']),
|
|
setIndex: _nullableIntFromJson(json['setIndex']),
|
|
passageIndex: _nullableIntFromJson(json['passageIndex']),
|
|
stepIndex: _nullableIntFromJson(json['stepIndex']),
|
|
programSnapshotId: _nullableStringFromJson(json['programSnapshotId']),
|
|
exerciseSnapshotId: _nullableStringFromJson(json['exerciseSnapshotId']),
|
|
stepSnapshotId: _nullableStringFromJson(json['stepSnapshotId']),
|
|
heartRateBpm: _nullableIntFromJson(json['heartRateBpm']),
|
|
distanceMeters: _nullableDoubleFromJson(json['distanceMeters']),
|
|
caloriesKcal: _nullableDoubleFromJson(json['caloriesKcal']),
|
|
);
|
|
}
|
|
|
|
final int schemaVersion;
|
|
final String? sampleId;
|
|
final String sessionId;
|
|
final int capturedAtEpochMs;
|
|
final int? programIndex;
|
|
final int? exerciseIndex;
|
|
final int? setIndex;
|
|
final int? passageIndex;
|
|
final int? stepIndex;
|
|
final String? programSnapshotId;
|
|
final String? exerciseSnapshotId;
|
|
final String? stepSnapshotId;
|
|
final int? heartRateBpm;
|
|
final double? distanceMeters;
|
|
final double? caloriesKcal;
|
|
|
|
int get recordedAtEpochMs => capturedAtEpochMs;
|
|
|
|
Map<String, Object?> toJson() {
|
|
return {
|
|
'schemaVersion': schemaVersion,
|
|
'sampleId': sampleId,
|
|
'sessionId': sessionId,
|
|
'capturedAtEpochMs': capturedAtEpochMs,
|
|
'recordedAtEpochMs': capturedAtEpochMs,
|
|
'programIndex': programIndex,
|
|
'exerciseIndex': exerciseIndex,
|
|
'setIndex': setIndex,
|
|
'passageIndex': passageIndex,
|
|
'stepIndex': stepIndex,
|
|
'programSnapshotId': programSnapshotId,
|
|
'exerciseSnapshotId': exerciseSnapshotId,
|
|
'stepSnapshotId': stepSnapshotId,
|
|
'heartRateBpm': heartRateBpm,
|
|
'distanceMeters': distanceMeters,
|
|
'caloriesKcal': caloriesKcal,
|
|
};
|
|
}
|
|
|
|
@override
|
|
bool operator ==(Object other) {
|
|
return identical(this, other) ||
|
|
other is WatchSensorSample &&
|
|
schemaVersion == other.schemaVersion &&
|
|
sampleId == other.sampleId &&
|
|
sessionId == other.sessionId &&
|
|
capturedAtEpochMs == other.capturedAtEpochMs &&
|
|
programIndex == other.programIndex &&
|
|
exerciseIndex == other.exerciseIndex &&
|
|
setIndex == other.setIndex &&
|
|
passageIndex == other.passageIndex &&
|
|
stepIndex == other.stepIndex &&
|
|
programSnapshotId == other.programSnapshotId &&
|
|
exerciseSnapshotId == other.exerciseSnapshotId &&
|
|
stepSnapshotId == other.stepSnapshotId &&
|
|
heartRateBpm == other.heartRateBpm &&
|
|
distanceMeters == other.distanceMeters &&
|
|
caloriesKcal == other.caloriesKcal;
|
|
}
|
|
|
|
@override
|
|
int get hashCode {
|
|
return Object.hash(
|
|
schemaVersion,
|
|
sampleId,
|
|
sessionId,
|
|
capturedAtEpochMs,
|
|
programIndex,
|
|
exerciseIndex,
|
|
setIndex,
|
|
passageIndex,
|
|
stepIndex,
|
|
programSnapshotId,
|
|
exerciseSnapshotId,
|
|
stepSnapshotId,
|
|
heartRateBpm,
|
|
distanceMeters,
|
|
caloriesKcal,
|
|
);
|
|
}
|
|
}
|
|
|
|
typedef WatchTelemetrySummary = WatchSensorSummary;
|
|
typedef WatchTelemetrySample = WatchSensorSample;
|
|
|
|
final class WatchTimerProjection {
|
|
const WatchTimerProjection({
|
|
required this.kind,
|
|
required this.label,
|
|
required this.displayMode,
|
|
required this.runState,
|
|
required this.referenceEpochMs,
|
|
required this.accumulatedMs,
|
|
this.startedAtEpochMs,
|
|
this.targetMs,
|
|
});
|
|
|
|
factory WatchTimerProjection.fromJson(Map<String, Object?> json) {
|
|
return WatchTimerProjection(
|
|
kind: _enumFromJson(
|
|
json['kind'],
|
|
WatchTimerKind.values,
|
|
WatchTimerKind.setTimer,
|
|
),
|
|
label: _stringFromJson(json['label']),
|
|
displayMode: _enumFromJson(
|
|
json['displayMode'],
|
|
WatchTimerDisplayMode.values,
|
|
WatchTimerDisplayMode.elapsed,
|
|
),
|
|
runState: _enumFromJson(
|
|
json['runState'],
|
|
WatchTimerRunState.values,
|
|
WatchTimerRunState.stopped,
|
|
),
|
|
referenceEpochMs: _intFromJson(json['referenceEpochMs'], 0),
|
|
accumulatedMs: _intFromJson(json['accumulatedMs'], 0),
|
|
startedAtEpochMs: _nullableIntFromJson(json['startedAtEpochMs']),
|
|
targetMs: _nullableIntFromJson(json['targetMs']),
|
|
);
|
|
}
|
|
|
|
final WatchTimerKind kind;
|
|
final String label;
|
|
final WatchTimerDisplayMode displayMode;
|
|
final WatchTimerRunState runState;
|
|
final int referenceEpochMs;
|
|
final int accumulatedMs;
|
|
final int? startedAtEpochMs;
|
|
final int? targetMs;
|
|
|
|
Map<String, Object?> toJson() {
|
|
return {
|
|
'kind': kind.name,
|
|
'label': label,
|
|
'displayMode': displayMode.name,
|
|
'runState': runState.name,
|
|
'referenceEpochMs': referenceEpochMs,
|
|
'accumulatedMs': accumulatedMs,
|
|
'startedAtEpochMs': startedAtEpochMs,
|
|
'targetMs': targetMs,
|
|
};
|
|
}
|
|
|
|
@override
|
|
bool operator ==(Object other) {
|
|
return identical(this, other) ||
|
|
other is WatchTimerProjection &&
|
|
kind == other.kind &&
|
|
label == other.label &&
|
|
displayMode == other.displayMode &&
|
|
runState == other.runState &&
|
|
referenceEpochMs == other.referenceEpochMs &&
|
|
accumulatedMs == other.accumulatedMs &&
|
|
startedAtEpochMs == other.startedAtEpochMs &&
|
|
targetMs == other.targetMs;
|
|
}
|
|
|
|
@override
|
|
int get hashCode {
|
|
return Object.hash(
|
|
kind,
|
|
label,
|
|
displayMode,
|
|
runState,
|
|
referenceEpochMs,
|
|
accumulatedMs,
|
|
startedAtEpochMs,
|
|
targetMs,
|
|
);
|
|
}
|
|
}
|
|
|
|
T _enumFromJson<T extends Enum>(Object? value, List<T> values, T fallback) {
|
|
if (value is String) {
|
|
for (final enumValue in values) {
|
|
if (enumValue.name == value) {
|
|
return enumValue;
|
|
}
|
|
}
|
|
}
|
|
return fallback;
|
|
}
|
|
|
|
T? _nullableEnumFromJson<T extends Enum>(Object? value, List<T> values) {
|
|
if (value is String) {
|
|
for (final enumValue in values) {
|
|
if (enumValue.name == value) {
|
|
return enumValue;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
List<T> _enumListFromJson<T extends Enum>(Object? value, List<T> values) {
|
|
if (value is! List) {
|
|
return const [];
|
|
}
|
|
return [
|
|
for (final item in value)
|
|
if (item is String)
|
|
for (final enumValue in values)
|
|
if (enumValue.name == item) enumValue,
|
|
];
|
|
}
|
|
|
|
WatchTimerProjection? _timerFromJson(Object? value) {
|
|
if (value is! Map) {
|
|
return null;
|
|
}
|
|
return WatchTimerProjection.fromJson(Map<String, Object?>.from(value));
|
|
}
|
|
|
|
List<WatchTimerProjection> _timerListFromJson(Object? value) {
|
|
if (value is! List) {
|
|
return const [];
|
|
}
|
|
return [
|
|
for (final item in value)
|
|
if (item is Map)
|
|
WatchTimerProjection.fromJson(Map<String, Object?>.from(item)),
|
|
];
|
|
}
|
|
|
|
String _stringFromJson(Object? value) {
|
|
return value is String ? value : '';
|
|
}
|
|
|
|
String? _nullableStringFromJson(Object? value) {
|
|
return value is String ? value : null;
|
|
}
|
|
|
|
int _intFromJson(Object? value, int fallback) {
|
|
return value is int ? value : fallback;
|
|
}
|
|
|
|
int? _nullableIntFromJson(Object? value) {
|
|
return value is int ? value : null;
|
|
}
|
|
|
|
double? _nullableDoubleFromJson(Object? value) {
|
|
return switch (value) {
|
|
double() => value,
|
|
int() => value.toDouble(),
|
|
_ => null,
|
|
};
|
|
}
|
|
|
|
bool _boolFromJson(Object? value, bool fallback) {
|
|
return value is bool ? value : fallback;
|
|
}
|
|
|
|
bool _listEquals<T>(List<T> left, List<T> right) {
|
|
if (identical(left, right)) {
|
|
return true;
|
|
}
|
|
if (left.length != right.length) {
|
|
return false;
|
|
}
|
|
for (var index = 0; index < left.length; index += 1) {
|
|
if (left[index] != right[index]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|