Files
arcx-app/lib/data/local/models/point_record.dart
T

147 lines
3.6 KiB
Dart

import 'package:isar/isar.dart';
part 'point_record.g.dart';
enum PointRecordStatus {
draft,
completed,
}
@embedded
class HitPoint {
HitPoint({
this.arrowIndex = 0,
this.endIndex = 0,
this.normalizedX = 0,
this.normalizedY = 0,
this.score,
this.isMiss = false,
});
int arrowIndex;
int endIndex;
/// Range: -1.0 ~ 1.0. The painter can map the normalized coordinate
/// directly onto different target canvases.
double normalizedX;
double normalizedY;
int? score;
bool isMiss;
}
@collection
class PointRecord {
PointRecord();
Id id = Isar.autoIncrement;
@Index(type: IndexType.value)
late DateTime updatedAt;
@Index(type: IndexType.value)
late DateTime createdAt;
@Index(type: IndexType.value)
DateTime? completedAt;
@enumerated
PointRecordStatus status = PointRecordStatus.draft;
/// Matches [BowOption.id] from point book config.
@Index(type: IndexType.value)
int bowOptionId = 1;
late String bowName;
/// Matches [TargetOption.id] from point book config.
@Index(type: IndexType.value)
int targetOptionId = 1;
late String targetName;
late String title;
int distanceMeters = 18;
int endCount = 6;
int arrowsPerEnd = 6;
String? note;
List<int> scores = <int>[];
List<HitPoint> hitPoints = <HitPoint>[];
bool get isDraft => status == PointRecordStatus.draft;
int get totalArrows => scores.length;
int get totalScore => scores.fold<int>(0, (sum, item) => sum + item);
double? get averageScore =>
scores.isEmpty ? null : totalScore / scores.length;
factory PointRecord.createDraft({
required int bowOptionId,
required String bowName,
required int targetOptionId,
required String targetName,
required int distanceMeters,
required int endCount,
required int arrowsPerEnd,
String? title,
DateTime? now,
}) {
final current = now ?? DateTime.now();
return PointRecord()
..title = title ?? '未完成记分'
..status = PointRecordStatus.draft
..bowOptionId = bowOptionId
..bowName = bowName
..targetOptionId = targetOptionId
..targetName = targetName
..distanceMeters = distanceMeters
..endCount = endCount
..arrowsPerEnd = arrowsPerEnd
..createdAt = current
..updatedAt = current;
}
PointRecord markCompleted({DateTime? completedAt}) {
final current = completedAt ?? DateTime.now();
return PointRecord()
..id = id
..title = title
..status = PointRecordStatus.completed
..bowOptionId = bowOptionId
..bowName = bowName
..targetOptionId = targetOptionId
..targetName = targetName
..distanceMeters = distanceMeters
..endCount = endCount
..arrowsPerEnd = arrowsPerEnd
..note = note
..scores = List<int>.from(scores)
..hitPoints = List<HitPoint>.from(hitPoints)
..createdAt = createdAt
..updatedAt = current
..completedAt = current;
}
/// Returns a draft copy with updated scores/hit points (used while editing).
PointRecord copyWithScores(List<int> scores, List<HitPoint> hitPoints) {
return PointRecord()
..id = id
..title = title
..status = status
..bowOptionId = bowOptionId
..bowName = bowName
..targetOptionId = targetOptionId
..targetName = targetName
..distanceMeters = distanceMeters
..endCount = endCount
..arrowsPerEnd = arrowsPerEnd
..note = note
..scores = List<int>.from(scores)
..hitPoints = List<HitPoint>.from(hitPoints)
..createdAt = createdAt
..updatedAt = DateTime.now()
..completedAt = completedAt;
}
}