PACKET v1.0.0 - Initial release

App móvil Flutter para capturar contenido multimedia, etiquetarlo con hashes y enviarlo a backends configurables.

Features:
- Captura de fotos, audio, video y archivos
- Sistema de etiquetas con bibliotecas externas (HST)
- Packs de etiquetas predefinidos
- Cola de reintentos (hasta 20 contenedores)
- Soporte GPS
- Hash SHA-256 auto-generado por contenedor
- Persistencia SQLite local
- Múltiples destinos configurables

Stack: Flutter 3.38.5, flutter_bloc, sqflite, dio

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
tzzrgit
2025-12-21 18:10:27 +01:00
commit dac0c51483
163 changed files with 8603 additions and 0 deletions

View File

@@ -0,0 +1,53 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../data/repositories/config_repository.dart';
import '../../../domain/entities/destino.dart';
import 'app_state.dart';
class AppCubit extends Cubit<AppState> {
final ConfigRepository _configRepo = ConfigRepository();
AppCubit() : super(const AppState());
Future<void> init() async {
emit(state.copyWith(isLoading: true));
final destinos = await _configRepo.getDestinos();
final activo = await _configRepo.getDestinoActivo();
emit(state.copyWith(
destinos: destinos,
destinoActivo: activo,
isLoading: false,
));
}
void setIndex(int index) {
emit(state.copyWith(currentIndex: index));
}
Future<void> setDestinoActivo(Destino destino) async {
if (destino.id != null) {
await _configRepo.setDestinoActivo(destino.id!);
emit(state.copyWith(destinoActivo: destino));
}
}
Future<void> addDestino(Destino destino) async {
final id = await _configRepo.insertDestino(destino);
final newDestino = destino.copyWith(id: id);
final destinos = [...state.destinos, newDestino];
emit(state.copyWith(destinos: destinos));
if (state.destinoActivo == null) {
await setDestinoActivo(newDestino);
}
}
Future<void> removeDestino(int id) async {
await _configRepo.deleteDestino(id);
final destinos = state.destinos.where((d) => d.id != id).toList();
emit(state.copyWith(destinos: destinos));
if (state.destinoActivo?.id == id) {
emit(state.copyWith(
destinoActivo: destinos.isNotEmpty ? destinos.first : null,
));
}
}
}

View File

@@ -0,0 +1,32 @@
import 'package:equatable/equatable.dart';
import '../../../domain/entities/destino.dart';
class AppState extends Equatable {
final int currentIndex;
final Destino? destinoActivo;
final List<Destino> destinos;
final bool isLoading;
const AppState({
this.currentIndex = 0,
this.destinoActivo,
this.destinos = const [],
this.isLoading = false,
});
AppState copyWith({
int? currentIndex,
Destino? destinoActivo,
List<Destino>? destinos,
bool? isLoading,
}) =>
AppState(
currentIndex: currentIndex ?? this.currentIndex,
destinoActivo: destinoActivo ?? this.destinoActivo,
destinos: destinos ?? this.destinos,
isLoading: isLoading ?? this.isLoading,
);
@override
List<Object?> get props => [currentIndex, destinoActivo, destinos, isLoading];
}