152 lines
3.4 KiB
Dart
152 lines
3.4 KiB
Dart
import 'package:isar/isar.dart';
|
|
|
|
part 'point_record.g.dart';
|
|
|
|
enum PointRecordStatus {
|
|
draft,
|
|
completed,
|
|
}
|
|
|
|
enum BowType {
|
|
recurve,
|
|
compound,
|
|
barebow,
|
|
traditional,
|
|
longbow,
|
|
other,
|
|
}
|
|
|
|
enum TargetFaceType {
|
|
cm40,
|
|
cm60,
|
|
cm80,
|
|
cm122,
|
|
vegas3Spot,
|
|
vertical3Spot,
|
|
custom,
|
|
}
|
|
|
|
@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;
|
|
|
|
@enumerated
|
|
BowType bowType = BowType.recurve;
|
|
|
|
@enumerated
|
|
TargetFaceType targetFaceType = TargetFaceType.cm40;
|
|
|
|
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 BowType bowType,
|
|
required TargetFaceType targetFaceType,
|
|
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
|
|
..bowType = bowType
|
|
..targetFaceType = targetFaceType
|
|
..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
|
|
..bowType = bowType
|
|
..targetFaceType = targetFaceType
|
|
..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
|
|
..bowType = bowType
|
|
..targetFaceType = targetFaceType
|
|
..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;
|
|
}
|
|
}
|