premier app version beta

This commit is contained in:
2026-01-18 13:38:09 +01:00
commit 031d4a4e17
164 changed files with 13698 additions and 0 deletions

View File

@@ -0,0 +1,112 @@
import 'shot.dart';
import 'target_type.dart';
class Session {
final String id;
final TargetType targetType;
final String imagePath;
final List<Shot> shots;
final int totalScore;
final double? groupingDiameter;
final double? groupingCenterX;
final double? groupingCenterY;
final DateTime createdAt;
final String? notes;
// Target detection data
final double? targetCenterX;
final double? targetCenterY;
final double? targetRadius;
Session({
required this.id,
required this.targetType,
required this.imagePath,
required this.shots,
required this.totalScore,
this.groupingDiameter,
this.groupingCenterX,
this.groupingCenterY,
required this.createdAt,
this.notes,
this.targetCenterX,
this.targetCenterY,
this.targetRadius,
});
int get shotCount => shots.length;
double get averageScore => shots.isEmpty ? 0.0 : totalScore / shots.length;
Session copyWith({
String? id,
TargetType? targetType,
String? imagePath,
List<Shot>? shots,
int? totalScore,
double? groupingDiameter,
double? groupingCenterX,
double? groupingCenterY,
DateTime? createdAt,
String? notes,
double? targetCenterX,
double? targetCenterY,
double? targetRadius,
}) {
return Session(
id: id ?? this.id,
targetType: targetType ?? this.targetType,
imagePath: imagePath ?? this.imagePath,
shots: shots ?? this.shots,
totalScore: totalScore ?? this.totalScore,
groupingDiameter: groupingDiameter ?? this.groupingDiameter,
groupingCenterX: groupingCenterX ?? this.groupingCenterX,
groupingCenterY: groupingCenterY ?? this.groupingCenterY,
createdAt: createdAt ?? this.createdAt,
notes: notes ?? this.notes,
targetCenterX: targetCenterX ?? this.targetCenterX,
targetCenterY: targetCenterY ?? this.targetCenterY,
targetRadius: targetRadius ?? this.targetRadius,
);
}
Map<String, dynamic> toMap() {
return {
'id': id,
'target_type': targetType.name,
'image_path': imagePath,
'total_score': totalScore,
'grouping_diameter': groupingDiameter,
'grouping_center_x': groupingCenterX,
'grouping_center_y': groupingCenterY,
'created_at': createdAt.toIso8601String(),
'notes': notes,
'target_center_x': targetCenterX,
'target_center_y': targetCenterY,
'target_radius': targetRadius,
};
}
factory Session.fromMap(Map<String, dynamic> map, List<Shot> shots) {
return Session(
id: map['id'] as String,
targetType: TargetType.fromString(map['target_type'] as String),
imagePath: map['image_path'] as String,
shots: shots,
totalScore: map['total_score'] as int,
groupingDiameter: map['grouping_diameter'] as double?,
groupingCenterX: map['grouping_center_x'] as double?,
groupingCenterY: map['grouping_center_y'] as double?,
createdAt: DateTime.parse(map['created_at'] as String),
notes: map['notes'] as String?,
targetCenterX: map['target_center_x'] as double?,
targetCenterY: map['target_center_y'] as double?,
targetRadius: map['target_radius'] as double?,
);
}
@override
String toString() {
return 'Session(id: $id, targetType: $targetType, shots: ${shots.length}, totalScore: $totalScore, createdAt: $createdAt)';
}
}

72
lib/data/models/shot.dart Normal file
View File

@@ -0,0 +1,72 @@
class Shot {
final String id;
final double x; // Relative position (0.0 - 1.0)
final double y; // Relative position (0.0 - 1.0)
final int score;
final String sessionId;
Shot({
required this.id,
required this.x,
required this.y,
required this.score,
required this.sessionId,
});
Shot copyWith({
String? id,
double? x,
double? y,
int? score,
String? sessionId,
}) {
return Shot(
id: id ?? this.id,
x: x ?? this.x,
y: y ?? this.y,
score: score ?? this.score,
sessionId: sessionId ?? this.sessionId,
);
}
Map<String, dynamic> toMap() {
return {
'id': id,
'x': x,
'y': y,
'score': score,
'session_id': sessionId,
};
}
factory Shot.fromMap(Map<String, dynamic> map) {
return Shot(
id: map['id'] as String,
x: (map['x'] as num).toDouble(),
y: (map['y'] as num).toDouble(),
score: map['score'] as int,
sessionId: map['session_id'] as String,
);
}
@override
String toString() {
return 'Shot(id: $id, x: $x, y: $y, score: $score, sessionId: $sessionId)';
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is Shot &&
other.id == id &&
other.x == x &&
other.y == y &&
other.score == score &&
other.sessionId == sessionId;
}
@override
int get hashCode {
return id.hashCode ^ x.hashCode ^ y.hashCode ^ score.hashCode ^ sessionId.hashCode;
}
}

View File

@@ -0,0 +1,84 @@
import 'target_type.dart';
class Target {
final String id;
final TargetType type;
final String imagePath;
final DateTime createdAt;
// Detected target bounds (relative coordinates 0.0-1.0)
final double? centerX;
final double? centerY;
final double? radius; // For concentric targets
final double? width; // For silhouette targets
final double? height; // For silhouette targets
Target({
required this.id,
required this.type,
required this.imagePath,
required this.createdAt,
this.centerX,
this.centerY,
this.radius,
this.width,
this.height,
});
Target copyWith({
String? id,
TargetType? type,
String? imagePath,
DateTime? createdAt,
double? centerX,
double? centerY,
double? radius,
double? width,
double? height,
}) {
return Target(
id: id ?? this.id,
type: type ?? this.type,
imagePath: imagePath ?? this.imagePath,
createdAt: createdAt ?? this.createdAt,
centerX: centerX ?? this.centerX,
centerY: centerY ?? this.centerY,
radius: radius ?? this.radius,
width: width ?? this.width,
height: height ?? this.height,
);
}
Map<String, dynamic> toMap() {
return {
'id': id,
'type': type.name,
'image_path': imagePath,
'created_at': createdAt.toIso8601String(),
'center_x': centerX,
'center_y': centerY,
'radius': radius,
'width': width,
'height': height,
};
}
factory Target.fromMap(Map<String, dynamic> map) {
return Target(
id: map['id'] as String,
type: TargetType.fromString(map['type'] as String),
imagePath: map['image_path'] as String,
createdAt: DateTime.parse(map['created_at'] as String),
centerX: map['center_x'] as double?,
centerY: map['center_y'] as double?,
radius: map['radius'] as double?,
width: map['width'] as double?,
height: map['height'] as double?,
);
}
@override
String toString() {
return 'Target(id: $id, type: $type, imagePath: $imagePath, createdAt: $createdAt)';
}
}

View File

@@ -0,0 +1,16 @@
enum TargetType {
concentric('Concentrique', 'Cible avec anneaux concentriques'),
silhouette('Silhouette', 'Cible en forme de silhouette');
final String displayName;
final String description;
const TargetType(this.displayName, this.description);
static TargetType fromString(String value) {
return TargetType.values.firstWhere(
(type) => type.name == value,
orElse: () => TargetType.concentric,
);
}
}