The data model always meant sale offers to carry an informational price (data-model §2.8, sharing-model §4.4); with offer state collapsed onto the Lot, the price lives there. Null amount on a sell lot = 'to be agreed' — the NIP-99 event simply omits the price tag. - schema v11: Lots.price_amount/price_currency, guarded migration, schema dump + generated schema_v11 for the round-trip test - ShareableLot/VarietyLot carry the price (sell-only in shareableLots); addLot/updateLot persist it and clear it when the lot leaves sale - OffersCubit.publishLots forwards it (outbox flush picks it up free) - lot sheet: price + currency inputs revealed only on 'For sale', with the €/Ğ1/hours quick-picks extracted to a shared CurrencyQuickPicks widget (reused by the sale sheet) - backup JSON round-trips the new columns - i18n share.price/priceHint in en/es/pt/ast
193 lines
5.1 KiB
Dart
193 lines
5.1 KiB
Dart
import 'dart:async';
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:commons_core/commons_core.dart';
|
|
import 'package:drift/drift.dart' show Value;
|
|
import 'package:equatable/equatable.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
|
|
import '../data/variety_repository.dart';
|
|
import '../db/enums.dart';
|
|
|
|
class VarietyDetailState extends Equatable {
|
|
const VarietyDetailState({
|
|
this.detail,
|
|
this.loading = true,
|
|
this.deleted = false,
|
|
});
|
|
|
|
final VarietyDetail? detail;
|
|
final bool loading;
|
|
final bool deleted;
|
|
|
|
@override
|
|
List<Object?> get props => [detail, loading, deleted];
|
|
}
|
|
|
|
/// Streams one variety's detail and edits it through the repository.
|
|
class VarietyDetailCubit extends Cubit<VarietyDetailState> {
|
|
VarietyDetailCubit(this._repo, this.varietyId)
|
|
: super(const VarietyDetailState()) {
|
|
_sub = _repo
|
|
.watchVariety(varietyId)
|
|
.listen(
|
|
(d) => emit(
|
|
VarietyDetailState(
|
|
detail: d,
|
|
loading: false,
|
|
deleted: state.deleted,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
final VarietyRepository _repo;
|
|
final String varietyId;
|
|
late final StreamSubscription<VarietyDetail?> _sub;
|
|
|
|
Future<void> updateFields({
|
|
String? label,
|
|
String? category,
|
|
String? notes,
|
|
bool? isOrganic,
|
|
bool? needsReproduction,
|
|
Value<int?> sowMonths = const Value.absent(),
|
|
Value<int?> transplantMonths = const Value.absent(),
|
|
Value<int?> floweringMonths = const Value.absent(),
|
|
Value<int?> fruitingMonths = const Value.absent(),
|
|
Value<int?> seedHarvestMonths = const Value.absent(),
|
|
}) => _repo.updateVariety(
|
|
id: varietyId,
|
|
label: label,
|
|
category: category,
|
|
notes: notes,
|
|
isOrganic: isOrganic,
|
|
needsReproduction: needsReproduction,
|
|
sowMonths: sowMonths,
|
|
transplantMonths: transplantMonths,
|
|
floweringMonths: floweringMonths,
|
|
fruitingMonths: fruitingMonths,
|
|
seedHarvestMonths: seedHarvestMonths,
|
|
);
|
|
|
|
Future<void> addLot({
|
|
LotType type = LotType.seed,
|
|
int? year,
|
|
int? month,
|
|
Quantity? quantity,
|
|
Presentation? presentation,
|
|
String? originName,
|
|
String? originPlace,
|
|
Abundance? abundance,
|
|
PreservationFormat? preservationFormat,
|
|
OfferStatus offerStatus = OfferStatus.private,
|
|
double? priceAmount,
|
|
String? priceCurrency,
|
|
}) => _repo.addLot(
|
|
varietyId: varietyId,
|
|
type: type,
|
|
harvestYear: year,
|
|
harvestMonth: month,
|
|
quantity: quantity,
|
|
presentation: presentation,
|
|
originName: originName,
|
|
originPlace: originPlace,
|
|
abundance: abundance,
|
|
preservationFormat: preservationFormat,
|
|
offerStatus: offerStatus,
|
|
priceAmount: priceAmount,
|
|
priceCurrency: priceCurrency,
|
|
);
|
|
|
|
Future<void> updateLot({
|
|
required String lotId,
|
|
required LotType type,
|
|
int? year,
|
|
int? month,
|
|
Quantity? quantity,
|
|
Presentation? presentation,
|
|
String? originName,
|
|
String? originPlace,
|
|
Abundance? abundance,
|
|
PreservationFormat? preservationFormat,
|
|
OfferStatus offerStatus = OfferStatus.private,
|
|
double? priceAmount,
|
|
String? priceCurrency,
|
|
}) => _repo.updateLot(
|
|
lotId: lotId,
|
|
type: type,
|
|
harvestYear: year,
|
|
harvestMonth: month,
|
|
quantity: quantity,
|
|
presentation: presentation,
|
|
originName: originName,
|
|
originPlace: originPlace,
|
|
abundance: abundance,
|
|
preservationFormat: preservationFormat,
|
|
offerStatus: offerStatus,
|
|
priceAmount: priceAmount,
|
|
priceCurrency: priceCurrency,
|
|
);
|
|
|
|
Future<void> deleteLot(String lotId) => _repo.softDeleteLot(lotId);
|
|
|
|
Future<void> addVernacularName(String name) =>
|
|
_repo.addVernacularName(varietyId, name);
|
|
|
|
Future<void> removeVernacularName(String nameId) =>
|
|
_repo.removeVernacularName(nameId);
|
|
|
|
Future<void> addPhoto(Uint8List bytes) => _repo.addPhoto(varietyId, bytes);
|
|
|
|
Future<void> removePhoto(String attachmentId) =>
|
|
_repo.removePhoto(attachmentId);
|
|
|
|
Future<void> setPreferredPhoto(String attachmentId) =>
|
|
_repo.setPreferredPhoto(varietyId, attachmentId);
|
|
|
|
Future<void> addExternalLink(String url, {String? title}) =>
|
|
_repo.addExternalLink(varietyId, url, title: title);
|
|
|
|
Future<void> removeExternalLink(String linkId) =>
|
|
_repo.removeExternalLink(linkId);
|
|
|
|
Future<void> linkSpecies(String speciesId) =>
|
|
_repo.linkSpecies(varietyId, speciesId);
|
|
|
|
Future<void> addGerminationTest({
|
|
required String lotId,
|
|
int? testedOn,
|
|
int? sampleSize,
|
|
int? germinatedCount,
|
|
}) => _repo.addGerminationTest(
|
|
lotId: lotId,
|
|
testedOn: testedOn,
|
|
sampleSize: sampleSize,
|
|
germinatedCount: germinatedCount,
|
|
);
|
|
|
|
Future<void> addConditionCheck({
|
|
required String lotId,
|
|
int? checkedOn,
|
|
int? containerCount,
|
|
DesiccantState? desiccantState,
|
|
}) => _repo.addConditionCheck(
|
|
lotId: lotId,
|
|
checkedOn: checkedOn,
|
|
containerCount: containerCount,
|
|
desiccantState: desiccantState,
|
|
);
|
|
|
|
Future<void> deleteVariety() async {
|
|
await _repo.softDeleteVariety(varietyId);
|
|
emit(
|
|
VarietyDetailState(detail: state.detail, loading: false, deleted: true),
|
|
);
|
|
}
|
|
|
|
@override
|
|
Future<void> close() async {
|
|
await _sub.cancel();
|
|
return super.close();
|
|
}
|
|
}
|