Flutter ProviderListener при ответе сервера с замороженной реализацией
В этом коде реализации, который я отправляю и получаю ответ от сервера, у меня есть поле в каждом ответе, и я обработал это с помощью
freezed
библиотека, и я хотел бы слушать этот класс как
success
способ показать что-то вроде
SnakeBar
@freezed
class ValidateCodeRequestState<T> with _$ValidateCodeRequestState {
const factory ValidateCodeRequestState.idle() = Idle<T>;
const factory ValidateCodeRequestState.loading() = Loading<T>;
const factory ValidateCodeRequestState.success(T? data) = Success<T>;
const factory ValidateCodeRequestState.error(Object error, StackTrace stackTrace) = Error<T>;
}
данные ответа сервера:
{
"message":"something",
"statusCode":-1,
...
}
и я хочу послушать
statusCode
с
ProviderListen
, но я не могу, например:
ProviderListener<ValidateCodeRequestState>(
provider: validateCodeRequestState,
onChange: (_, validateCodeRequestState) {
if (weatherStateNotifier.state.statusCode == 1) {
...
}
}
StateNotifier
:
class ValidateCodeRequestStateNotifier<T> extends StateNotifier<ValidateCodeRequestState<T>> {
ValidateCodeRequestStateNotifier() : super(const ValidateCodeRequestState.idle());
Future<ValidateCodeRequestState<T>> makeRequest(Future<T> Function() sendDioConnectionRequest)async{
try{
state = ValidateCodeRequestState<T>.loading();
final response = await sendDioConnectionRequest();
final newState = ValidateCodeRequestState<T>.success(response);
if(mounted){
state = newState;
}
return newState;
}on DioError catch(error,stackTrace){
final newState = ValidateCodeRequestState<T>.error(error, stackTrace);
if(mounted){
state = newState;
}
return newState;
}
}
}
репозиторий:
final validateCodeRepositoryProvider = Provider((ref) => ValidateCodeRepository(ref.read));
final validateCodeProvider =
StateNotifierProvider<ValidateCodeRequestNotifier, ValidateCodeRequestState<ValidateCodeResponseStructure>>(
(ref) => ValidateCodeRequestNotifier(ref.watch(validateCodeRepositoryProvider)));
class ValidateCodeRepository {
final Reader _reader;
ValidateCodeRepository(this._reader);
Future<ValidateCodeResponseStructure> getValidateCodeResponse(String mobileNumber, String validateCode) async {
try {
const r = RetryOptions(maxAttempts: 3);
final response = await r.retry(
() => _reader(dioProvider)
.post(
Server.$verifyCode,
queryParameters: {'mobile_number': mobileNumber, 'validate_code': validateCode},
options: Options(headers: {'Content-Type': 'application/json'}),
)
.timeout(const Duration(seconds: 3)),
retryIf: (e) => e is SocketException || e is TimeoutException);
return ValidateCodeResponseStructure.fromJson(response.data as Map<String, dynamic>);
} on DioError catch (e) {
throw e.error as Object;
//FlutterE
}
}
}
class ValidateCodeRequestNotifier extends ValidateCodeRequestStateNotifier<ValidateCodeResponseStructure> {
final ValidateCodeRepository _validateCodeRepository;
ValidateCodeRequestNotifier(this._validateCodeRepository);
Future<ValidateCodeRequestState<ValidateCodeResponseStructure>> checkValidateCode(
String mobileNumber, String validateCode) =>
makeRequest(() => _validateCodeRepository.getValidateCodeResponse(mobileNumber, validateCode));
}
и структура ответа:
@freezed
class ValidateCodeResponseStructure with _$ValidateCodeResponseStructure {
const factory ValidateCodeResponseStructure({
required String message,
required int statusCode,
}) = _ValidateCodeResponseStructure;
factory ValidateCodeResponseStructure.fromJson(Map<String, dynamic> json) => _$ValidateCodeResponseStructureFromJson(json);
}
3 ответа
Решение
Я исправил проблемы,
increment
метод должен быть:
void increment(int productId, int serviceId, int serviceCost) {
final newState = OrderStructure(state.title, state.address, state.lat, state.lang, state.pelak, state.vahed, []);
for (final product in state.products) {
if (product.id == productId) {
if (product.services.any((s) => s.id == serviceId)) {
final service = product.services.firstWhere((s) => s.id == serviceId);
newState.products.add(SelectedProducts(productId, [
...product.services.where((s) => s.id != serviceId),
SelectedProductServices(service.id, service.count + 1, service.cost)
]));
} else {
newState.products.add(
SelectedProducts(productId, [...product.services, SelectedProductServices(serviceId, 1, serviceCost)]));
}
} else {
newState.products.add(product);
}
}
if (!newState.products.any((p) => p.id == productId) ||
!newState.products.firstWhere((p) => p.id == productId).services.any((s) => s.id == serviceId)) {
// Add new
newState.products.add(SelectedProducts(productId, [SelectedProductServices(serviceId, 1, serviceCost)]));
}
state = newState;
}
спасибо TimWhiting
Вам нужно сделать что-то подобное.
void increment(int productId, int serviceId, int serviceCost) {
// copy the old state
final newState = OrderStructure(state.title, [...state.products]);
bool updated = false;
/// We directly iterate on the newState.
for(final product in newState.products){
if( product.id != productId ) {
continue; // jump to next the product because the current product do not match.
}
updated = true; // We are sure that the product already exist.
// We search the first index of service that has `id` equal to `serviceId`.
final serviceIndex = product.services.indexWhere( (s) => s.id == serviceId );
if( serviceIndex >= 0 ) {
product.services[serviceIndex].count ++;
break;
}
final newService = SelectedProductServices(serviceId, 1, serviceCost);
product.services.add(newService);
break;
}
// Now we only check if we have not made an update.
if(!update) {
final newService = SelectedProductServices(serviceId, 1, serviceCost);
final newProduct = SelectedProduct(productId, [newService]);
newState.products.add(newProduct);
}
}
Вам не нужно обновлять все
OrderStructure
, только ссылка на внутренний список, содержащий обновляемую службу:
void increment({required int productId, required int serviceId, required int serviceCost}) {
final OrderStructure order = state;
final int productIndex = order.products.indexWhere((product) => product.id == productId);
final SelectedProducts product;
// If the product has not been found, add it to the products
if (productIndex == -1) {
product = SelectedProducts(productId, []);
order.products.add(product);
// Otherwise, just get it
} else {
product = order.products[productIndex];
}
final int serviceIndex = product.services.indexWhere((service) => service.id == serviceId && service.cost == serviceCost);
// If the service has not been found, add it to the services
if (serviceIndex == -1) {
product.services.add(SelectedProductServices(serviceId, 1, serviceCost));
// Otherwise, just update its counter
} else {
final SelectedProductServices service = product.services[serviceIndex];
product.services[serviceIndex] = SelectedProductServices(service.id, service.count + 1, service.cost);
}
// Set the state to the updated order structure
state = order;
}
Для декремента просто сделайте
service.count - 1
в последней строке.