Merge remote-tracking branch 'origin/feature/contacts' into fusion-app

This commit is contained in:
2026-03-25 02:30:09 +01:00
11 changed files with 66 additions and 36 deletions

View File

@@ -25,7 +25,7 @@ class ContactsScreen extends ConsumerWidget {
contactsViewModelProvider.select((s) => s.errorMessage),
(previous, next) {
if (next.isNotEmpty) {
showTopSnackbar(context, message: next, type: MessageType.error);
showTopSnackbar(context, message: context.translate(next), type: MessageType.error);
}
},
);
@@ -58,14 +58,21 @@ class ContactsScreen extends ConsumerWidget {
shape: const CircleBorder(),
child: InkWell(
customBorder: const CircleBorder(),
onTap: () => showDialog(
context: context,
builder: (_) => const Dialog(
backgroundColor: Colors.transparent,
child: NewContactDialog(),
),
),
child: SizedBox(
onTap: () {
if (state.contacts.length == state.maxLimit) {
showTopSnackbar(context, message: context.translate(I18n.errorContactsMax));
return;
}
showDialog(
context: context,
builder: (_) => const Dialog(
backgroundColor: Colors.transparent,
child: NewContactDialog(),
),
);
},
child: SizedBox(
width: SizeUtils.getByScreen(small: 48, big: 46),
height: SizeUtils.getByScreen(small: 48, big: 46),
child: Icon(

View File

@@ -134,6 +134,11 @@ class ContactsViewModel extends Notifier<ContactsViewState> {
Future<bool> deleteContact(ContactEntity contact) async {
if (state.isLoading) return false;
if (state.contacts.length == 1){
state = state.copyWith(errorMessage: I18n.errorContactsMin);
return true;
}
try {
state = state.copyWith(isLoading: true, errorMessage: '');

View File

@@ -8,9 +8,10 @@ part 'contacts_view_state.freezed.dart';
abstract class ContactsViewState with _$ContactsViewState {
const factory ContactsViewState({
@Default([]) List<ContactEntity> contacts,
@Default(10) int maxLimit,
@Default('+34') String dialCode,
@Default(true) bool isLoading,
@Default(false) bool isEditing,
@Default('') String errorMessage,
@Default('') String errorMessage
}) = _ContactsViewState;
}

View File

@@ -14,7 +14,7 @@ T _$identity<T>(T value) => value;
/// @nodoc
mixin _$ContactsViewState {
List<ContactEntity> get contacts; String get dialCode; bool get isLoading; bool get isEditing; String get errorMessage;
List<ContactEntity> get contacts; int get maxLimit; String get dialCode; bool get isLoading; bool get isEditing; String get errorMessage;
/// Create a copy of ContactsViewState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@@ -25,16 +25,16 @@ $ContactsViewStateCopyWith<ContactsViewState> get copyWith => _$ContactsViewStat
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is ContactsViewState&&const DeepCollectionEquality().equals(other.contacts, contacts)&&(identical(other.dialCode, dialCode) || other.dialCode == dialCode)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isEditing, isEditing) || other.isEditing == isEditing)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage));
return identical(this, other) || (other.runtimeType == runtimeType&&other is ContactsViewState&&const DeepCollectionEquality().equals(other.contacts, contacts)&&(identical(other.maxLimit, maxLimit) || other.maxLimit == maxLimit)&&(identical(other.dialCode, dialCode) || other.dialCode == dialCode)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isEditing, isEditing) || other.isEditing == isEditing)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage));
}
@override
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(contacts),dialCode,isLoading,isEditing,errorMessage);
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(contacts),maxLimit,dialCode,isLoading,isEditing,errorMessage);
@override
String toString() {
return 'ContactsViewState(contacts: $contacts, dialCode: $dialCode, isLoading: $isLoading, isEditing: $isEditing, errorMessage: $errorMessage)';
return 'ContactsViewState(contacts: $contacts, maxLimit: $maxLimit, dialCode: $dialCode, isLoading: $isLoading, isEditing: $isEditing, errorMessage: $errorMessage)';
}
@@ -45,7 +45,7 @@ abstract mixin class $ContactsViewStateCopyWith<$Res> {
factory $ContactsViewStateCopyWith(ContactsViewState value, $Res Function(ContactsViewState) _then) = _$ContactsViewStateCopyWithImpl;
@useResult
$Res call({
List<ContactEntity> contacts, String dialCode, bool isLoading, bool isEditing, String errorMessage
List<ContactEntity> contacts, int maxLimit, String dialCode, bool isLoading, bool isEditing, String errorMessage
});
@@ -62,10 +62,11 @@ class _$ContactsViewStateCopyWithImpl<$Res>
/// Create a copy of ContactsViewState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? contacts = null,Object? dialCode = null,Object? isLoading = null,Object? isEditing = null,Object? errorMessage = null,}) {
@pragma('vm:prefer-inline') @override $Res call({Object? contacts = null,Object? maxLimit = null,Object? dialCode = null,Object? isLoading = null,Object? isEditing = null,Object? errorMessage = null,}) {
return _then(_self.copyWith(
contacts: null == contacts ? _self.contacts : contacts // ignore: cast_nullable_to_non_nullable
as List<ContactEntity>,dialCode: null == dialCode ? _self.dialCode : dialCode // ignore: cast_nullable_to_non_nullable
as List<ContactEntity>,maxLimit: null == maxLimit ? _self.maxLimit : maxLimit // ignore: cast_nullable_to_non_nullable
as int,dialCode: null == dialCode ? _self.dialCode : dialCode // ignore: cast_nullable_to_non_nullable
as String,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
as bool,isEditing: null == isEditing ? _self.isEditing : isEditing // ignore: cast_nullable_to_non_nullable
as bool,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable
@@ -154,10 +155,10 @@ return $default(_that);case _:
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( List<ContactEntity> contacts, String dialCode, bool isLoading, bool isEditing, String errorMessage)? $default,{required TResult orElse(),}) {final _that = this;
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( List<ContactEntity> contacts, int maxLimit, String dialCode, bool isLoading, bool isEditing, String errorMessage)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _ContactsViewState() when $default != null:
return $default(_that.contacts,_that.dialCode,_that.isLoading,_that.isEditing,_that.errorMessage);case _:
return $default(_that.contacts,_that.maxLimit,_that.dialCode,_that.isLoading,_that.isEditing,_that.errorMessage);case _:
return orElse();
}
@@ -175,10 +176,10 @@ return $default(_that.contacts,_that.dialCode,_that.isLoading,_that.isEditing,_t
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( List<ContactEntity> contacts, String dialCode, bool isLoading, bool isEditing, String errorMessage) $default,) {final _that = this;
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( List<ContactEntity> contacts, int maxLimit, String dialCode, bool isLoading, bool isEditing, String errorMessage) $default,) {final _that = this;
switch (_that) {
case _ContactsViewState():
return $default(_that.contacts,_that.dialCode,_that.isLoading,_that.isEditing,_that.errorMessage);case _:
return $default(_that.contacts,_that.maxLimit,_that.dialCode,_that.isLoading,_that.isEditing,_that.errorMessage);case _:
throw StateError('Unexpected subclass');
}
@@ -195,10 +196,10 @@ return $default(_that.contacts,_that.dialCode,_that.isLoading,_that.isEditing,_t
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( List<ContactEntity> contacts, String dialCode, bool isLoading, bool isEditing, String errorMessage)? $default,) {final _that = this;
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( List<ContactEntity> contacts, int maxLimit, String dialCode, bool isLoading, bool isEditing, String errorMessage)? $default,) {final _that = this;
switch (_that) {
case _ContactsViewState() when $default != null:
return $default(_that.contacts,_that.dialCode,_that.isLoading,_that.isEditing,_that.errorMessage);case _:
return $default(_that.contacts,_that.maxLimit,_that.dialCode,_that.isLoading,_that.isEditing,_that.errorMessage);case _:
return null;
}
@@ -210,7 +211,7 @@ return $default(_that.contacts,_that.dialCode,_that.isLoading,_that.isEditing,_t
class _ContactsViewState implements ContactsViewState {
const _ContactsViewState({final List<ContactEntity> contacts = const [], this.dialCode = '+34', this.isLoading = true, this.isEditing = false, this.errorMessage = ''}): _contacts = contacts;
const _ContactsViewState({final List<ContactEntity> contacts = const [], this.maxLimit = 10, this.dialCode = '+34', this.isLoading = true, this.isEditing = false, this.errorMessage = ''}): _contacts = contacts;
final List<ContactEntity> _contacts;
@@ -220,6 +221,7 @@ class _ContactsViewState implements ContactsViewState {
return EqualUnmodifiableListView(_contacts);
}
@override@JsonKey() final int maxLimit;
@override@JsonKey() final String dialCode;
@override@JsonKey() final bool isLoading;
@override@JsonKey() final bool isEditing;
@@ -235,16 +237,16 @@ _$ContactsViewStateCopyWith<_ContactsViewState> get copyWith => __$ContactsViewS
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ContactsViewState&&const DeepCollectionEquality().equals(other._contacts, _contacts)&&(identical(other.dialCode, dialCode) || other.dialCode == dialCode)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isEditing, isEditing) || other.isEditing == isEditing)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage));
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ContactsViewState&&const DeepCollectionEquality().equals(other._contacts, _contacts)&&(identical(other.maxLimit, maxLimit) || other.maxLimit == maxLimit)&&(identical(other.dialCode, dialCode) || other.dialCode == dialCode)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isEditing, isEditing) || other.isEditing == isEditing)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage));
}
@override
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_contacts),dialCode,isLoading,isEditing,errorMessage);
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_contacts),maxLimit,dialCode,isLoading,isEditing,errorMessage);
@override
String toString() {
return 'ContactsViewState(contacts: $contacts, dialCode: $dialCode, isLoading: $isLoading, isEditing: $isEditing, errorMessage: $errorMessage)';
return 'ContactsViewState(contacts: $contacts, maxLimit: $maxLimit, dialCode: $dialCode, isLoading: $isLoading, isEditing: $isEditing, errorMessage: $errorMessage)';
}
@@ -255,7 +257,7 @@ abstract mixin class _$ContactsViewStateCopyWith<$Res> implements $ContactsViewS
factory _$ContactsViewStateCopyWith(_ContactsViewState value, $Res Function(_ContactsViewState) _then) = __$ContactsViewStateCopyWithImpl;
@override @useResult
$Res call({
List<ContactEntity> contacts, String dialCode, bool isLoading, bool isEditing, String errorMessage
List<ContactEntity> contacts, int maxLimit, String dialCode, bool isLoading, bool isEditing, String errorMessage
});
@@ -272,10 +274,11 @@ class __$ContactsViewStateCopyWithImpl<$Res>
/// Create a copy of ContactsViewState
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? contacts = null,Object? dialCode = null,Object? isLoading = null,Object? isEditing = null,Object? errorMessage = null,}) {
@override @pragma('vm:prefer-inline') $Res call({Object? contacts = null,Object? maxLimit = null,Object? dialCode = null,Object? isLoading = null,Object? isEditing = null,Object? errorMessage = null,}) {
return _then(_ContactsViewState(
contacts: null == contacts ? _self._contacts : contacts // ignore: cast_nullable_to_non_nullable
as List<ContactEntity>,dialCode: null == dialCode ? _self.dialCode : dialCode // ignore: cast_nullable_to_non_nullable
as List<ContactEntity>,maxLimit: null == maxLimit ? _self.maxLimit : maxLimit // ignore: cast_nullable_to_non_nullable
as int,dialCode: null == dialCode ? _self.dialCode : dialCode // ignore: cast_nullable_to_non_nullable
as String,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
as bool,isEditing: null == isEditing ? _self.isEditing : isEditing // ignore: cast_nullable_to_non_nullable
as bool,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable

View File

@@ -661,5 +661,7 @@
"activityMeterPedometerEnabled": "Schrittzähler aktiviert",
"activityMeterPedometerDisabled": "Schrittzähler deaktiviert",
"errorActivityData": "Aktivitätsdaten konnten nicht geladen werden",
"errorPedometer": "Der Schrittzähler konnte nicht aktualisiert werden"
"errorPedometer": "Der Schrittzähler konnte nicht aktualisiert werden",
"errorContactsMin": "Das Gerät muss mindestens einen Kontakt haben",
"errorContactsMax": "Das Gerät kann nicht mehr als 10 Kontakte haben"
}

View File

@@ -793,5 +793,7 @@
"activityMeterPedometerEnabled": "Pedometer enabled",
"activityMeterPedometerDisabled": "Pedometer disabled",
"errorActivityData": "Could not load activity data",
"errorPedometer": "Could not update pedometer"
"errorPedometer": "Could not update pedometer",
"errorContactsMin": "The device must have at least one contact",
"errorContactsMax": "The device cannot have more than 10 contacts"
}

View File

@@ -791,5 +791,7 @@
"activityMeterPedometerEnabled": "Podómetro activado",
"activityMeterPedometerDisabled": "Podómetro desactivado",
"errorActivityData": "No se pudieron cargar los datos de actividad",
"errorPedometer": "No se pudo actualizar el podómetro"
"errorPedometer": "No se pudo actualizar el podómetro",
"errorContactsMin": "El dispositivo debe tener al menos un contacto",
"errorContactsMax": "El dispositivo no puede tener más de 10 contactos"
}

View File

@@ -661,5 +661,7 @@
"activityMeterPedometerEnabled": "Podomètre activé",
"activityMeterPedometerDisabled": "Podomètre désactivé",
"errorActivityData": "Impossible de charger les données d'activité",
"errorPedometer": "Impossible de mettre à jour le podomètre"
"errorPedometer": "Impossible de mettre à jour le podomètre",
"errorContactsMin": "L'appareil doit avoir au moins un contact",
"errorContactsMax": "L'appareil ne peut pas avoir plus de 10 contacts"
}

View File

@@ -661,5 +661,7 @@
"activityMeterPedometerEnabled": "Contapassi attivato",
"activityMeterPedometerDisabled": "Contapassi disattivato",
"errorActivityData": "Impossibile caricare i dati di attività",
"errorPedometer": "Impossibile aggiornare il contapassi"
"errorPedometer": "Impossibile aggiornare il contapassi",
"errorContactsMin": "Il dispositivo deve avere almeno un contatto",
"errorContactsMax": "Il dispositivo non può avere più di 10 contatti"
}

View File

@@ -661,5 +661,7 @@
"activityMeterPedometerEnabled": "Pedómetro ativado",
"activityMeterPedometerDisabled": "Pedómetro desativado",
"errorActivityData": "Não foi possível carregar os dados de atividade",
"errorPedometer": "Não foi possível atualizar o pedómetro"
"errorPedometer": "Não foi possível atualizar o pedómetro",
"errorContactsMin": "O dispositivo deve ter pelo menos um contacto",
"errorContactsMax": "O dispositivo não pode ter mais de 10 contactos"
}

View File

@@ -798,4 +798,6 @@ class I18n {
static const String activityMeterPedometerDisabled = 'activityMeterPedometerDisabled';
static const String errorActivityData = 'errorActivityData';
static const String errorPedometer = 'errorPedometer';
static const String errorContactsMin = 'errorContactsMin';
static const String errorContactsMax = 'errorContactsMax';
}