Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"permissions": {
"allow": [
"mcp__github__list_issues",
"Bash(gh issue:*)",
"Bash(bash scripts/propagate-version.sh)",
"Bash(dart format:*)",
"Bash(flutter analyze:*)",
"Bash(flutter test:*)",
"Bash(bash scripts/propagate-version.sh --check)",
"Bash(gh pr:*)"
]
}
}
2 changes: 1 addition & 1 deletion assets/version.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"version": "0.1.16"}
{"version": "0.1.17"}
56 changes: 56 additions & 0 deletions lib/features/apgar/domain/apgar_calculator.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import 'package:emerkit/shared/domain/entities/severity.dart';

class ApgarResult {
final int appearance;
final int pulse;
final int grimace;
final int activity;
final int respiration;
final int total;
final Severity severity;

const ApgarResult({
required this.appearance,
required this.pulse,
required this.grimace,
required this.activity,
required this.respiration,
required this.total,
required this.severity,
});
}

class ApgarCalculator {
const ApgarCalculator();

ApgarResult calculate({
required int appearance,
required int pulse,
required int grimace,
required int activity,
required int respiration,
}) {
final total = appearance + pulse + grimace + activity + respiration;
return ApgarResult(
appearance: appearance,
pulse: pulse,
grimace: grimace,
activity: activity,
respiration: respiration,
total: total,
severity: _severity(total),
);
}

Severity _severity(int total) {
if (total >= 7) {
return const Severity(label: 'Normal', level: SeverityLevel.mild);
}
if (total >= 4) {
return const Severity(
label: 'Depresion moderada', level: SeverityLevel.moderate);
}
return const Severity(
label: 'Depresion severa', level: SeverityLevel.severe);
}
}
72 changes: 72 additions & 0 deletions lib/features/apgar/domain/apgar_data.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import 'package:emerkit/shared/domain/entities/scored_item.dart';
import 'package:emerkit/shared/domain/entities/clinical_reference.dart';

class ApgarData {
ApgarData._();

static const appearanceResponses = [
ScoredItem(label: 'Completamente rosado', score: 2),
ScoredItem(label: 'Acrocianosis', score: 1),
ScoredItem(label: 'Cianosis/palidez generalizada', score: 0),
];

static const pulseResponses = [
ScoredItem(label: '\u2265 100 lpm', score: 2),
ScoredItem(label: '< 100 lpm', score: 1),
ScoredItem(label: 'Ausente', score: 0),
];

static const grimaceResponses = [
ScoredItem(label: 'Llanto vigoroso, tos/estornudo', score: 2),
ScoredItem(label: 'Mueca, llanto debil', score: 1),
ScoredItem(label: 'Sin respuesta', score: 0),
];

static const activityResponses = [
ScoredItem(label: 'Movimiento activo', score: 2),
ScoredItem(label: 'Flexion debil', score: 1),
ScoredItem(label: 'Flacido', score: 0),
];

static const respirationResponses = [
ScoredItem(label: 'Llanto fuerte, regular', score: 2),
ScoredItem(label: 'Lenta, irregular', score: 1),
ScoredItem(label: 'Ausente', score: 0),
];

static const infoSections = <String, String>{
'\u00bfQue es?':
'El Test de Apgar es una escala de valoracion neonatal desarrollada por Virginia Apgar en 1952. '
'Evalua cinco parametros del recien nacido (Apariencia, Pulso, Gesticulacion, Actividad y '
'Respiracion) al minuto 1 y 5 de vida. Es la herramienta estandar para la evaluacion rapida '
'del estado del neonato tras el nacimiento.',
'Interpretacion': '7-10: Normal (recien nacido en buenas condiciones)\n'
'4-6: Depresion moderada (puede requerir estimulacion o soporte)\n'
'0-3: Depresion severa (requiere reanimacion inmediata)\n\n'
'Se evalua al minuto 1 (estado inicial) y al minuto 5 (respuesta a reanimacion).\n'
'Si Apgar a los 5 minutos < 7, se repite cada 5 minutos hasta los 20 minutos.',
'Cuando aplicarlo': 'Atencion al parto extrahospitalario\n'
'Nacimiento en domicilio, via publica o ambulancia\n'
'Valoracion inicial del recien nacido\n'
'Seguimiento de la respuesta a reanimacion neonatal',
'Limitaciones': 'Es una valoracion subjetiva y puede variar entre observadores.\n'
'No predice mortalidad ni morbilidad neurologica a largo plazo por si solo.\n'
'Prematuros pueden tener puntuaciones mas bajas sin implicar patologia.\n'
'No sustituye la monitorizacion continua del recien nacido.',
};

static const references = [
ClinicalReference(
'Apgar V. A proposal for a new method of evaluation of the newborn infant. Curr Res Anesth Analg. 1953;32(4):260-267.',
),
ClinicalReference(
'American Academy of Pediatrics Committee on Fetus and Newborn. The Apgar Score. Pediatrics. 2015;136(4):819-822.',
),
ClinicalReference(
'Neonatal Resuscitation Program (NRP). 8th Edition. AAP, 2021.',
),
ClinicalReference(
'ERC Guidelines 2025. Resuscitation and support of transition of babies at birth.',
),
];
}
115 changes: 115 additions & 0 deletions lib/features/apgar/presentation/apgar_screen.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import 'package:flutter/material.dart';
import 'package:emerkit/shared/domain/entities/severity.dart';
import 'package:emerkit/shared/presentation/theme/app_colors.dart';
import 'package:emerkit/shared/presentation/widgets/tool_screen_base.dart';
import 'package:emerkit/shared/presentation/widgets/result_banner.dart';
import 'package:emerkit/shared/presentation/widgets/scored_item_selector.dart';
import 'package:emerkit/shared/presentation/widgets/tool_info_panel.dart';
import '../domain/apgar_calculator.dart';
import '../domain/apgar_data.dart';

class ApgarScreen extends StatefulWidget {
const ApgarScreen({super.key});

@override
State<ApgarScreen> createState() => _ApgarScreenState();
}

class _ApgarScreenState extends State<ApgarScreen> {
static const _calculator = ApgarCalculator();
int _appearance = 2,
_pulse = 2,
_grimace = 2,
_activity = 2,
_respiration = 2;

ApgarResult get _result => _calculator.calculate(
appearance: _appearance,
pulse: _pulse,
grimace: _grimace,
activity: _activity,
respiration: _respiration,
);

void _reset() => setState(() {
_appearance = 2;
_pulse = 2;
_grimace = 2;
_activity = 2;
_respiration = 2;
});

@override
Widget build(BuildContext context) {
final r = _result;
return ToolScreenBase(
title: 'Test de Apgar',
onReset: _reset,
resultWidget: ResultBanner(
value: '${r.total}',
label: r.severity.label,
subtitle:
'A: ${r.appearance} P: ${r.pulse} G: ${r.grimace} A: ${r.activity} R: ${r.respiration}',
color: r.severity.level.color,
severityLevel: r.severity.level,
),
toolBody: ListView(
padding: const EdgeInsets.all(12),
children: [
ScoredItemSelector(
title: 'Apariencia (A)',
icon: Icons.palette,
items: ApgarData.appearanceResponses,
selectedScore: _appearance,
onChanged: (v) => setState(() => _appearance = v),
),
ScoredItemSelector(
title: 'Pulso (P)',
icon: Icons.favorite,
items: ApgarData.pulseResponses,
selectedScore: _pulse,
onChanged: (v) => setState(() => _pulse = v),
),
ScoredItemSelector(
title: 'Gesticulacion (G)',
icon: Icons.sentiment_satisfied,
items: ApgarData.grimaceResponses,
selectedScore: _grimace,
onChanged: (v) => setState(() => _grimace = v),
),
ScoredItemSelector(
title: 'Actividad (A)',
icon: Icons.fitness_center,
items: ApgarData.activityResponses,
selectedScore: _activity,
onChanged: (v) => setState(() => _activity = v),
),
ScoredItemSelector(
title: 'Respiracion (R)',
icon: Icons.air,
items: ApgarData.respirationResponses,
selectedScore: _respiration,
onChanged: (v) => setState(() => _respiration = v),
),
],
),
infoBody: const ToolInfoPanel(
sections: ApgarData.infoSections,
references: ApgarData.references,
),
);
}
}

extension _SeverityColor on SeverityLevel {
Color get color {
switch (this) {
case SeverityLevel.mild:
return AppColors.severityMild;
case SeverityLevel.moderate:
return AppColors.severityModerate;
case SeverityLevel.severe:
return AppColors.severitySevere;
}
}
}
6 changes: 6 additions & 0 deletions lib/features/home/presentation/tool_registry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,12 @@ class ToolRegistry {
icon: Icons.science_outlined,
route: '/diluciones',
category: ToolCategory.tecnicas),
ToolEntry(
id: 'apgar',
name: 'Apgar',
icon: Icons.child_friendly,
route: '/apgar',
category: ToolCategory.valoracion),
// Protección
ToolEntry(
id: 'epi',
Expand Down
2 changes: 2 additions & 0 deletions lib/shared/presentation/router/app_router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import 'package:emerkit/features/gps_converter/presentation/gps_converter_screen
import 'package:emerkit/features/wallace/presentation/wallace_screen.dart';
import 'package:emerkit/features/shock_index/presentation/shock_index_screen.dart';
import 'package:emerkit/features/diluciones/presentation/diluciones_screen.dart';
import 'package:emerkit/features/apgar/presentation/apgar_screen.dart';

final appRouter = GoRouter(
initialLocation: '/',
Expand Down Expand Up @@ -80,5 +81,6 @@ final appRouter = GoRouter(
GoRoute(path: '/wallace', builder: (_, __) => const WallaceScreen()),
GoRoute(path: '/shock-index', builder: (_, __) => const ShockIndexScreen()),
GoRoute(path: '/diluciones', builder: (_, __) => const DilucionesScreen()),
GoRoute(path: '/apgar', builder: (_, __) => const ApgarScreen()),
],
);
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: emerkit
description: EmerKit - Herramientas clinicas para profesionales de emergencias
publish_to: 'none'
version: 0.1.16+116
version: 0.1.17+117

environment:
sdk: ^3.5.0
Expand Down
Loading